J'ai l'état suivant:
this.setState({ selected: { id: 1, name: 'Foobar' } });
Ensuite, je mets à jour l'état:
this.setState({ selected: { name: 'Barfoo' }});
Puisqu'il setState
est supposé fusionner, je m'attendrais à ce que ce soit:
{ selected: { id: 1, name: 'Barfoo' } };
Mais à la place, il mange l'identifiant et l'état est:
{ selected: { name: 'Barfoo' } };
Est-ce le comportement attendu et quelle est la solution pour mettre à jour une seule propriété d'un objet d'état imbriqué?
la source
this.setState({ selected: { ...this.state.selected, name: 'barfoo' } })
ce qui est traduit enthis.setState({ selected: _extends({}, this.state.selected, { name: 'barfoo' }) });
underscore
/lodash
. Faites-en sa propre réponse, s'il vous plaît.this.state
n'est pas nécessairement à jour . Vous pouvez obtenir des résultats inattendus en utilisant la méthode extend. Passer une fonction de mise à jour àsetState
est la bonne solution.Des assistants d'immuabilité ont été récemment ajoutés à React.addons, donc avec cela, vous pouvez maintenant faire quelque chose comme:
Documentation des aides d'immuabilité .
la source
React.addons.update()
méthode soit obsolète, mais la bibliothèque de remplacement github.com/kolodny/immutability-helper contient uneupdate()
fonction équivalente .Étant donné que de nombreuses réponses utilisent l'état actuel comme base pour fusionner de nouvelles données, je voulais souligner que cela peut casser. Les changements d'état sont mis en file d'attente et ne modifient pas immédiatement l'objet d'état d'un composant. Le fait de référencer les données d'état avant le traitement de la file d'attente vous donnera donc des données périmées qui ne reflètent pas les modifications en attente que vous avez apportées dans setState. À partir de la documentation:
Cela signifie que l'utilisation de l'état "actuel" comme référence dans les appels suivants à setState n'est pas fiable. Par exemple:
Si vous devez utiliser l'état actuel (par exemple pour fusionner des données dans un objet imbriqué), setState accepte alternativement une fonction comme argument au lieu d'un objet; la fonction est appelée après toutes les mises à jour précédentes de state, et transmet l'état en tant qu'argument - donc cela peut être utilisé pour apporter des modifications atomiques garanties de respecter les modifications précédentes.
la source
this.state
, qui peut être périmé (ou plutôt en attente de mise à jour en file d'attente) lorsque vous y accédez.Je ne voulais pas installer une autre bibliothèque alors voici encore une autre solution.
Au lieu de:
Faites ceci à la place:
Ou, grâce à @ icc97 dans les commentaires, encore plus succinctement mais sans doute moins lisible:
De plus, pour être clair, cette réponse ne viole aucune des préoccupations mentionnées ci-dessus par @bgannonpl.
la source
this.setState({ selected: Object.assign(this.state.selected, { name: "Barfoo" }));
Object.assign(a, b)
prend les attributs deb
, les insère / les écrasea
puis les retournea
. Les gens réagissent deviennent impitoyables si vous modifiez directement l'état.{}
comme premier argument:this.setState({ selected: Object.assign({}, this.state.selected, { name: "Barfoo" }) });
. Cela ne modifie pas l'état d'origine.Préserver l'état précédent en fonction de la réponse @bgannonpl:
Exemple de Lodash :
Pour vérifier que cela fonctionne correctement, vous pouvez utiliser le deuxième rappel de fonction de paramètre:
Je l'ai utilisé
merge
carextend
élimine les autres propriétés autrement.Exemple d' immutabilité de React :
la source
Ma solution pour ce genre de situation est d'utiliser, comme une autre réponse l'a souligné, les assistants Immuabilité .
Étant donné que la définition de l'état en profondeur est une situation courante, j'ai créé le mixin suivant:
Ce mixin est inclus dans la plupart de mes composants et je ne l'utilise généralement
setState
plus directement.Avec ce mixin, tout ce que vous avez à faire pour obtenir l'effet souhaité est d'appeler la fonction
setStateinDepth
de la manière suivante:Pour plus d'informations:
setStateinDepth
voir la documentation Immutability Helpers .la source
this.state.test.two
sera toujours là après la misethis.state.test.one
à jour en utilisantsetStateInDepth({test: {one: {$set: 'new-value'}}})
. J'utilise ce code dans tous mes composants afin de contourner lasetState
fonction limitée de React .this.state.test
tant que Array. Changer en objets, l'a résolu.J'utilise des classes es6, et je me suis retrouvé avec plusieurs objets complexes sur mon état supérieur et j'essayais de rendre mon composant principal plus modulaire, j'ai donc créé un wrapper de classe simple pour garder l'état sur le composant supérieur mais permettre plus de logique locale .
La classe wrapper prend une fonction comme constructeur qui définit une propriété sur l'état du composant principal.
Ensuite, pour chaque propriété complexe de l'état supérieur, je crée une classe StateWrapped. Vous pouvez définir les accessoires par défaut dans le constructeur ici et ils seront définis lorsque la classe est initialisée, vous pouvez vous référer à l'état local pour les valeurs et définir l'état local, faire référence aux fonctions locales et le faire passer dans la chaîne:
Donc, mon composant de niveau supérieur a juste besoin du constructeur pour définir chaque classe sur sa propriété d'état de niveau supérieur, un rendu simple et toutes les fonctions qui communiquent entre les composants.
Semble fonctionner assez bien pour mes besoins, gardez à l'esprit que vous ne pouvez pas changer l'état des propriétés que vous attribuez aux composants enveloppés au niveau du composant supérieur car chaque composant enveloppé suit son propre état mais met à jour l'état du composant supérieur à chaque fois qu'il change.
la source
À partir de maintenant,
selon la documentation https://reactjs.org/docs/react-component.html#setstate , en utilisant:
la source
Solution
Edit: Cette solution utilisait la syntaxe de diffusion . Le but était de créer un objet sans aucune référence à
prevState
, donc celaprevState
ne serait pas modifié. Mais dans mon utilisation,prevState
semblait être modifié parfois. Donc, pour un clonage parfait sans effets secondaires, nous convertissons maintenantprevState
en JSON, puis en arrière. (L'inspiration pour utiliser JSON est venue de MDN .)Rappelles toi:
setState(prevState => stateChange)
Pas
state
que vous souhaitez modifierLes étapes 3 et 4 peuvent être combinées sur une seule ligne.
Exemple
Exemple simplifié:
Cela suit parfaitement les directives React. Basé sur la réponse d' eicksl à une question similaire.
la source
Solution ES6
Nous définissons l'état au départ
Nous modifions une propriété à un certain niveau de l'objet d'état:
la source
L'état React n'effectue pas la fusion récursive
setState
alors qu'il s'attend à ce qu'il n'y ait pas de mises à jour des membres d'état sur place en même temps. Vous devez soit copier vous-même les objets / tableaux inclus (avec array.slice ou Object.assign) ou utiliser la bibliothèque dédiée.Comme celui-ci. NestedLink prend directement en charge la gestion de l'état React composé.
De plus, le lien vers le
selected
ouselected.name
peut être transmis partout comme un accessoire unique et modifié avecset
.la source
avez-vous défini l'état initial?
J'utiliserai une partie de mon propre code par exemple:
Dans une application sur laquelle je travaille, c'est ainsi que j'ai défini et utilisé l'état. Je crois que
setState
vous pouvez alors simplement modifier les états que vous voulez individuellement, je l'ai appelé ainsi:Gardez à l'esprit que vous devez définir l'état dans la
React.createClass
fonction que vous avez appeléegetInitialState
la source
J'utilise le tmp var pour changer.
la source
let original = {a:1}; let tmp = original; tmp.a = 5; // original is now === Object {a: 5}
Ne faites pas cela, même si cela ne vous a pas encore posé de problèmes.