Est-il possible de mettre à jour les propriétés d'un objet avec setState ?
Quelque chose comme :
this.state = {
jasper: { name: 'jasper', age: 28 },
}
J'ai essayé :
this.setState({jasper.name: 'someOtherName'});
et ceci :
this.setState({jasper: {name: 'someothername'}})
La première entraîne une erreur de syntaxe et la seconde ne donne rien. Avez-vous une idée ?
Il y a plusieurs façons de le faire, puisque la mise à jour de l'état est une [opération async][1], donc pour mettre à jour l'objet d'état, nous devons utiliser la [fonction updater][2] avec setState
.
1- La plus simple:
Créez d'abord une copie de jasper
puis effectuez les modifications dans celle-ci :
this.setState(prevState => {
let jasper = Object.assign({}, prevState.jasper); // creating copy of state variable jasper
jasper.name = 'someothername'; // update the name property, assign a new value
return { jasper }; // return new object jasper object
})
Au lieu d'utiliser Object.assign
, on peut aussi l'écrire comme ceci :
let jasper = { ...prevState.jasper };
2- Utilisation de [l'opérateur d'étalement][3] :
this.setState(prevState => ({
jasper: { // object that we want to update
...prevState.jasper, // keep all other key-value pairs
name: 'something' // update the value of specific key
}
}))
Note: Object.assign
et Spread Operator
ne créent que des [copies superficielles][4], donc si vous avez défini des objets imbriqués ou des tableaux d'objets, vous avez besoin d'une approche différente.
Supposons que vous ayez défini state comme :
this.state = {
food: {
sandwich: {
capsicum: true,
crackers: true,
mayonnaise: true
},
pizza: {
jalapeno: true,
extraCheese: false
}
}
}
Pour mettre à jour extraCheese de l'objet pizza :
this.setState(prevState => ({
food: {
...prevState.food, // copy all other key-value pairs of food object
pizza: { // specific object of food object
...prevState.food.pizza, // copy all pizza key-value pairs
extraCheese: true // update value of specific key
}
}
}))
Supposons que vous avez une application todo, et que vous gérez les données dans ce formulaire :
this.state = {
todoItems: [
{
name: 'Learn React Basics',
status: 'pending'
}, {
name: 'Check Codebase',
status: 'pending'
}
]
}
Pour mettre à jour le statut de n'importe quel objet todo, exécutez un map sur le tableau et vérifiez une valeur unique pour chaque objet, en cas de condition=true
, retournez le nouvel objet avec la valeur mise à jour, sinon le même objet.
let key = 2;
this.setState(prevState => ({
todoItems: prevState.todoItems.map(
el => el.key === key? { ...el, status: 'done' }: el
)
}))
Suggestion: Si l'objet n'a pas de valeur unique, utilisez l'index du tableau.
[1] : https://stackoverflow.com/questions/42593202/why-calling-setstate-method-doesnt-mutate-the-state-immediately/42593250#42593250 [2] : https://reactjs.org/docs/react-component.html#setstate [3] : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator [4] : https://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language
Le premier cas est effectivement une erreur de syntaxe.
Comme je ne peux pas voir le reste de votre composant, il est difficile de comprendre pourquoi vous imbriquez des objets dans votre état. Ce n'est pas une bonne idée d'imbriquer des objets dans l'état du composant. Essayez de définir votre état initial comme suit :
this.state = {
name: 'jasper',
age: 28
}
De cette façon, si vous voulez mettre à jour le nom, vous pouvez simplement appeler :
this.setState({
name: 'Sean'
});
Cela vous permettra-t-il d'atteindre votre objectif ?
Pour des magasins de données plus grands et plus complexes, j'utiliserais quelque chose comme Redux. Mais c'est beaucoup plus avancé.
La règle générale en matière d'état des composants est de ne l'utiliser que pour gérer l'état de l'interface utilisateur du composant (par exemple, actif, temporisation, etc.).
Consultez ces références :
Autre possibilité : définir votre variable à partir de l'objet Jasper, puis appeler simplement une variable.
Opérateur de diffusion : ES6
this.state = { jasper: { name: 'jasper', age: 28 } }
let foo = "something that needs to be saved into state"
this.setState(prevState => ({
jasper: {
...jasper.entity,
foo
}
})