Si j'ai un composant de réaction ayant une propriété définie sur son état:
onClick() {
this.setState({ foo: 'bar' });
}
Est-il possible de supprimer "foo"
ici de Object.keys(this.state)
?
La méthode replaceState ressemble à la méthode évidente à essayer, mais elle a été dépréciée depuis.
Vous pouvez définir foo
sur undefined
, comme suit
var Hello = React.createClass({
getInitialState: function () {
return {
foo: 10,
bar: 10
}
},
handleClick: function () {
this.setState({ foo: undefined });
},
render: function() {
return (
<div>
<div onClick={ this.handleClick.bind(this) }>Remove foo</div>
<div>Foo { this.state.foo }</div>
<div>Bar { this.state.bar }</div>
</div>
);
}
});
Aussi, vous pouvez utiliser delete
,
delete this.state.foo;
this.setState(this.state);
mais ceci est dangereux car cette solution manipule directement this.state
Mettre à jour
La solution précédente supprime simplement la valeur de foo
et key
et la compétence existe dans state
, si vous devez supprimer complètement la clé de state
, l'une des solutions possibles peut être setState
avec un parent key
, comme ceci
var Hello = React.createClass({
getInitialState: function () {
return {
data: {
foo: 10,
bar: 10
}
}
},
handleClick: function () {
const state = {
data: _.omit(this.state.data, 'foo')
};
this.setState(state, () => {
console.log(this.state);
});
},
render: function() {
return (
<div>
<div onClick={ this.handleClick }>Remove foo</div>
<div>Foo { this.state.data.foo }</div>
<div>Bar { this.state.data.bar }</div>
</div>
);
}
});
ReactDOM.render(<Hello />, document.getElementById('container'))
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>
Le code suivant supprimera foo
de this.state
sans modifier directement this.state
:
const {foo, ...state} = this.state;
this.setState({state});
Vous aurez besoin du préréglage stage 3 pour que cela fonctionne.
Solution précédente - est anti-modèle, parce que cela change cet état. Il est faux!
Utilisez ceci (à l'ancienne):
let newState = Object.assign({}, this.state) // Copy state
newState.foo = null // modyfy copyed object, not original state
// newState.foo = undefined // works too
// delete newState.foo // Wrong, do not do this
this.setState(newState) // set new state
Ou utilisez du sucre ES6:
this.setState({...o, a:undefined})
Assez gentil, n'est-ce pas? ))
Dans l'ancienne syntaxe de React (originale, pas ES6), cela a this.replaceState
, qui supprime les clés inutiles en magasin, mais maintenant c'est deprecated
Dans ReactCompositeComponent.js
, dans la source de React sur GitHub, il existe une méthode appelée _processPendingState
, qui est la méthode ultime qui implémente l'état de fusion à partir d'appels de composant.setState;
`` `. _processPendingState: function (props, context) { var inst = this._instance; file d'attente var = this._pendingStateQueue; var replace = this._pendingReplaceState; this._pendingReplaceState = false; this._pendingStateQueue = null;
if (!queue) {
return inst.state;
}
if (replace && queue.length === 1) {
return queue[0];
}
var nextState = replace ? queue[0] : inst.state;
var dontMutate = true;
for (var i = replace ? 1 : 0; i < queue.length; i++) {
var partial = queue[i];
let partialState = typeof partial === 'function'
? partial.call(inst, nextState, props, context)
: partial;
if (partialState) {
if (dontMutate) {
dontMutate = false;
nextState = Object.assign({}, nextState, partialState);
} else {
Object.assign(nextState, partialState);
}
}
}
`` `
Dans ce code, vous pouvez voir la ligne qui implémente la fusion;
nextState = Object.assign({}, nextState, partialState);
Nulle part dans cette fonction, il n’ya un appel à delete
ou similaire, ce qui signifie que ce comportement n’est pas vraiment prévu. De plus, copier complètement la statistique, supprimer la propriété et appeler setState ne fonctionneront pas, car setState est toujours une fusion. Par conséquent, la propriété supprimée sera simplement ignorée.
Notez également que setState ne fonctionne pas immédiatement, mais que les lots changent. Par conséquent, si vous essayez de cloner tout l'objet state et de ne modifier que les propriétés, vous pouvez effacer les appels précédents à setState. Comme le dit le document React;
React peut regrouper plusieurs appels setState () dans une seule mise à jour pour améliorer les performances.
Étant donné que this.props et this.state peuvent être mis à jour de manière asynchrone, vous ne devez pas compter sur leurs valeurs pour calculer l'état suivant.
Ce que vous pourriez chercher à faire est d’ajouter plus d’informations;
this.setState({ xSet: true, x: 'foo' });
this.setState({ xSet: false, x: undefined });
C’est moche, certes, mais cela vous donne l’information supplémentaire dont vous avez besoin pour différencier une valeur définie comme indéfinie d’une valeur non définie. De plus, il joue à Nice avec les composants internes de React, ses transactions, le traitement en lots des changements d’état et toute autre horreur. Mieux vaut prendre un peu plus de complexité ici que d'essayer de deviner les composants internes de Reacts, qui regorgent d'horreurs telles que la réconciliation des transactions, la gestion de fonctionnalités obsolètes telles que replaceState, etc.
Vous pouvez utiliser Object.assign
pour créer une copie superficielle de l'état de votre application à la profondeur appropriée et supprimer l'élément de votre copie. Ensuite, utilisez setState
pour fusionner votre copie modifiée dans l'état de l'application.
Ce n'est pas une solution parfaite. Copier un objet entier comme celui-ci peut entraîner des problèmes de performances/mémoire. La copie superficielle de Object.assign
permet d'atténuer les problèmes de mémoire/performances, mais vous devez également savoir quelles parties de votre nouvel objet sont des copies et quelles sont les références aux données dans l'état de l'application.
Dans l'exemple ci-dessous, la modification du tableau ingredients
modifierait en réalité directement l'état de l'application.
Définir la valeur de l'élément indésirable sur null
ou undefined
ne la supprime pas.
const Component = React.Component;
class App extends Component {
constructor(props) {
super(props);
this.state = {
"recipes": {
"1": {
"id": 1,
"name": "Pumpkin Pie",
"ingredients": [
"Pumpkin Puree",
"Sweetened Condensed Milk",
"Eggs",
"Pumpkin Pie Spice",
"Pie Crust"
]
},
"2": {
"id": 2,
"name": "Spaghetti",
"ingredients": [
"Noodles",
"Tomato Sauce",
"(Optional) Meatballs"
]
},
"3": {
"id": 3,
"name": "Onion Pie",
"ingredients": [
"Onion",
"Pie Crust",
"Chicken Soup Stock"
]
},
"4": {
"id": 4,
"name": "Chicken Noodle Soup",
"ingredients": [
"Chicken",
"Noodles",
"Chicken Stock"
]
}
},
"activeRecipe": "4",
"warningAction": {
"name": "Delete Chicken Noodle Soup",
"description": "delete the recipe for Chicken Noodle Soup"
}
};
this.renderRecipes = this.renderRecipes.bind(this);
this.deleteRecipe = this.deleteRecipe.bind(this);
}
deleteRecipe(e) {
const recipes = Object.assign({}, this.state.recipes);
const id = e.currentTarget.dataset.id;
delete recipes[id];
this.setState({ recipes });
}
renderRecipes() {
const recipes = [];
for (const id in this.state.recipes) {
recipes.Push((
<tr>
<td>
<button type="button" data-id={id} onClick={this.deleteRecipe}
>×</button>
</td>
<td>{this.state.recipes[id].name}</td>
</tr>
));
}
return recipes;
}
render() {
return (
<table>
{this.renderRecipes()}
</table>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<main id="app"></main>
Si la suppression est dans une fonction et que la clé doit être une variable, essayez ceci:
removekey = (keyname) => {
let newState = this.state;
delete newState[keyname];
this.setState({ newState })
}
this.removekey('thekey');
Presque la même chose que la réponse de steve, mais dans une fonction.
Je pense que c'est une bonne façon de s'y prendre =>
//in constructor
let state = {
sampleObject: {0: a, 1: b, 2: c }
}
//method
removeObjectFromState = (objectKey) => {
let reducedObject = {}
Object.keys(this.state.sampleObject).map((key) => {
if(key !== objectKey) reducedObject[key] = this.state.sampleObject[key];
})
this.setState({ sampleObject: reducedObject });
}
Si vous souhaitez réinitialiser complètement l'état (en supprimant un grand nombre d'éléments), ceci fonctionne comme suit:
this.setState(prevState => {
let newState = {};
Object.keys(prevState).forEach(k => {
newState[k] = undefined;
});
return newState;
});
L’utilisation de cette variante de setState
vous permet d’avoir accès à l’ensemble de l’état pendant l’appel, alors que this.state
pourrait être un peu obsolète (en raison des précédents appels setState
n'ayant pas encore été traités).