J'essaie d'organiser mon état en utilisant une propriété imbriquée comme ceci:
this.state = {
someProperty: {
flag:true
}
}
Mais la mise à jour de l'état comme ça,
this.setState({ someProperty.flag: false });
ne fonctionne pas. Comment cela peut-il être fait correctement?
javascript
reactjs
ecmascript-6
setstate
Alex Yong
la source
la source
Réponses:
Pour
setState
un objet imbriqué, vous pouvez suivre l'approche ci-dessous car je pense que setState ne gère pas les mises à jour imbriquées.L'idée est de créer un objet factice, d'effectuer des opérations dessus, puis de remplacer l'état du composant par l'objet mis à jour
Désormais, l'opérateur de propagation crée une seule copie imbriquée de niveau de l'objet. Si votre état est fortement imbriqué comme:
Vous pouvez définirState en utilisant l'opérateur de propagation à chaque niveau, comme
Cependant, la syntaxe ci-dessus devient laide à mesure que l'état devient de plus en plus imbriqué et je vous recommande donc d'utiliser le
immutability-helper
package pour mettre à jour l'état.Consultez cette réponse pour savoir comment mettre à jour l'état avec
immutability helper
.la source
someProperty
et nous lethis.setState((prevState) => ({nested: {...prevState.nested, propertyToSet: newValue}})
Un peu fastidieux...prevState,
dans le dernier exemple, vous seulsomeProperty
et ses enfantsPour l'écrire sur une seule ligne
la source
this.state
immédiatement aprèssetState
et attendez-vous à ce qu'il ait la nouvelle valeur. Versus appelant à l'this.state
intérieursetState
. Ou y a-t-il également un problème avec ce dernier qui n'est pas clair pour moi?this.state
aprèssetState
. D'ailleurs, nous ne passons pasthis.state
àsetState
. L'…
opérateur répartit les propriétés. C'est la même chose que Object.assign (). github.com/tc39/proposal-object-rest-spreadthis.setState(currentState => { someProperty: { ...currentState.someProperty, flag: false} });
pourrait permettre d'éviter ce problème?Parfois, les réponses directes ne sont pas les meilleures :)
Version courte:
ce code
devrait être simplifié comme quelque chose comme
Version longue:
Actuellement, vous ne devriez pas vouloir travailler avec un état imbriqué dans React . Parce que React n'est pas orienté pour fonctionner avec des états imbriqués et toutes les solutions proposées ici ressemblent à des hacks. Ils n'utilisent pas le cadre mais se battent avec lui. Ils suggèrent d'écrire un code moins clair dans le but douteux de regrouper certaines propriétés. Ils sont donc très intéressants comme réponse au défi mais pratiquement inutiles.
Imaginons l'état suivant:
Que se passera-t-il si vous modifiez uniquement une valeur de
child1
? React ne restitue pas la vue car il utilise une comparaison superficielle et il constate que laparent
propriété n'a pas changé. BTW muter directement l'objet d'état est considéré comme une mauvaise pratique en général.Vous devez donc recréer l'
parent
objet entier . Mais dans ce cas, nous rencontrerons un autre problème. React pensera que tous les enfants ont changé leurs valeurs et les restituera tous. Bien sûr, ce n'est pas bon pour la performance.Il est toujours possible de résoudre ce problème en écrivant une logique compliquée,
shouldComponentUpdate()
mais je préférerais m'arrêter ici et utiliser une solution simple à partir de la version courte.la source
Avertissement
la réponse à votre misère - voir l'exemple ici
Il existe un autre moyen plus court de mettre à jour la propriété imbriquée.
Sur une seule ligne
Remarque: Ceci est l' opérateur Comma ~ MDN , voyez-le en action ici (Sandbox) .
Il est similaire à (bien que cela ne change pas la référence d'état)
Pour la différence subtile dans ce contexte entre
forceUpdate
etsetState
voir l'exemple lié.Bien sûr, cela abuse de certains principes de base, car le
state
devrait être en lecture seule, mais puisque vous jetez immédiatement l'ancien état et le remplacez par un nouvel état, c'est tout à fait correct.Attention
Même si le composant contenant l'état se mettra à jour et se restituera correctement ( sauf ce gotcha ) , les accessoires ne se propageront pas aux enfants (voir le commentaire de Spymaster ci-dessous) . N'utilisez cette technique que si vous savez ce que vous faites.
Par exemple, vous pouvez passer un accessoire plat modifié qui est mis à jour et transmis facilement.
Maintenant, même si la référence à complexNestedProp n'a pas changé ( shouldComponentUpdate )
le composant se rendra à chaque mise à jour du composant parent, ce qui est le cas après l'appel
this.setState
outhis.forceUpdate
dans le parent.Effets de la mutation de l'État
L'utilisation de l' état imbriqué et la mutation directe de l'état est dangereuse car différents objets peuvent contenir (intentionnellement ou non) différentes références (plus anciennes) à l' état et ne savent pas nécessairement quand mettre à jour (par exemple lors de l'utilisation
PureComponent
ou sishouldComponentUpdate
est implémenté pour revenirfalse
) OU sont destiné à afficher les anciennes données comme dans l'exemple ci-dessous.Quoi qu'il en soit ici, vous pouvez voir
Nested PureChildClass
qu'il n'a pas été rendu à nouveau en raison de la non-propagation des accessoires.la source
state
complètement et utilise des propriétés observables personnalisées . React'ssetState
est juste une commodité intégrée, mais vous vous rendez vite compte qu'il a ses limites. L'utilisation de propriétés personnalisées et l'utilisation intelligente deforceUpdate
vous en donne beaucoup plus. Utilisez les observables au lieu de l'état dans les composants React.this.forceUpdate()
ou d'implémenter des éléments spécifiquesshouldComponentUpdate
.Si vous utilisez ES2015, vous avez accès à Object.assign. Vous pouvez l'utiliser comme suit pour mettre à jour un objet imbriqué.
Vous fusionnez les propriétés mises à jour avec celles existantes et utilisez l'objet renvoyé pour mettre à jour l'état.
Edit: ajout d'un objet vide comme cible à la fonction assign pour vous assurer que l'état n'est pas muté directement comme l'a souligné carkod.
la source
la source
property
contient plusieurs propriétés imbriquées, la première les supprimera, la seconde non. codesandbox.io/s/nameless-pine-42thuIl existe de nombreuses bibliothèques pour vous aider. Par exemple, en utilisant immutability-helper :
Utilisation de lodash / fp set:
Utilisation de la fusion lodash / fp :
la source
lodash
, vous voudrez probablement essayer de_.cloneDeep
définir l'état pour être la copie clonée.lodash/fp
, nous n'avons donc pas à nous soucier des mutations.merge
ou àset
fonctionner dans lodash / fp en plus de la syntaxe?this.setState(newState)
les méthodes lodash / fp. Un autre problème est que lodash.set
(non-fp) a un ordre d'arguments différent qui m'a fait trébucher pendant un certain temps.Nous utilisons Immer https://github.com/mweststrate/immer pour gérer ces types de problèmes.
Je viens de remplacer ce code dans l'un de nos composants
Avec ça
Avec immer, vous gérez votre état comme un "objet normal". La magie se produit derrière la scène avec des objets proxy.
la source
Voici une variante de la première réponse donnée dans ce fil de discussion qui ne nécessite pas de packages, bibliothèques ou fonctions spéciales supplémentaires.
Afin de définir l'état d'un champ imbriqué spécifique, vous avez défini l'objet entier. Je l' ai fait en créant une variable,
newState
et la diffusion du contenu de l'état actuel dans ce premier utilisant le ES2015 opérateur propagation . Ensuite, j'ai remplacé la valeur dethis.state.flag
par la nouvelle valeur (puisque j'ai définiflag: value
après avoir répandu l'état actuel dans l'objet, leflag
champ dans l'état actuel est remplacé). Ensuite, je règle simplement l'état desomeProperty
monnewState
objet.la source
Bien que l'imbrication ne soit pas vraiment la façon dont vous devez traiter un état de composant, parfois pour quelque chose de facile pour l'imbrication à un niveau.
Pour un État comme celui-ci
Une méthode réutilisable que j'utiliserais ressemblerait à ceci.
puis en passant simplement le nom d'obj pour chaque imbrication que vous souhaitez aborder ...
la source
J'ai utilisé cette solution.
Si vous avez un état imbriqué comme celui-ci:
vous pouvez déclarer la fonction handleChange qui copie l'état actuel et le réaffecte avec des valeurs modifiées
ici le html avec l'écouteur d'événement
la source
Créez une copie de l'état:
apporter des modifications à cet objet:
maintenant mettre à jour l'état
la source
Bien que vous ayez posé des questions sur un état du composant React basé sur une classe, le même problème existe avec le hook useState. Pire encore: le hook useState n'accepte pas les mises à jour partielles. Cette question est donc devenue très pertinente lorsque le crochet useState a été introduit.
J'ai décidé de poster la réponse suivante pour m'assurer que la question couvre des scénarios plus modernes où le crochet useState est utilisé:
Si vous avez:
vous pouvez définir la propriété imbriquée en clonant le courant et en corrigeant les segments requis des données, par exemple:
Ou vous pouvez utiliser la bibliothèque Immer pour simplifier le clonage et l'application de correctifs à l'objet.
Ou vous pouvez utiliser la bibliothèque Hookstate (avertissement: je suis un auteur) pour simplement gérer entièrement les données d'état complexes (locales et globales) et améliorer les performances (lire: ne vous inquiétez pas de l'optimisation du rendu):
obtenir le champ à rendre:
définissez le champ imbriqué:
Voici l'exemple Hookstate, où l'état est profondément / récursivement imbriqué dans une structure de données arborescente .
la source
Deux autres options non encore mentionnées:
la source
Pour rendre les choses génériques, j'ai travaillé sur les réponses de @ ShubhamKhatri et @ Qwerty.
objet d'état
contrôles d'entrée
Méthode updateState
setState as @ ShubhamKhatri's answer
setState as @ Qwerty's answer
Remarque: Ces méthodes ci-dessus ne fonctionneront pas pour les tableaux
la source
Je prends très au sérieux les préoccupations déjà exprimées concernant la création d'une copie complète de l'état de votre composant. Cela dit, je suggère fortement Immer .
Cela devrait fonctionner
React.PureComponent
(c'est-à-dire des comparaisons d'états superficiels par React) car ilImmer
utilise intelligemment un objet proxy pour copier efficacement un arbre d'état arbitrairement profond. Immer est également plus sûr pour les types par rapport aux bibliothèques comme Immutability Helper, et est idéal pour les utilisateurs Javascript et Typescript.Fonction utilitaire de frappe
la source
la source
obj
s'agit simplement d'une référence à l'État, donc à travers lui, vous mutez l'this.state
objet réelJ'ai trouvé que cela fonctionnait pour moi, ayant un formulaire de projet dans mon cas où, par exemple, vous avez un identifiant et un nom et je préfère maintenir l'état d'un projet imbriqué.
Faites le moi savoir!
la source
Quelque chose comme ça pourrait suffire,
la source
Je sais que c'est une vieille question, mais je voulais quand même partager comment j'ai réussi. En supposant que l'état dans le constructeur ressemble à ceci:
Ma
handleChange
fonction est comme ça:Et assurez-vous de nommer les entrées en conséquence:
la source
Je fais des mises à jour imbriquées avec une recherche réduite :
Exemple:
Les variables imbriquées dans l'état:
La fonction:
Utilisation:
la source
Ceci est mon état initial
Le crochet ou vous pouvez le remplacer par l'état (composant de classe)
La méthode de handleChange
Méthode pour définir un état avec des états imbriqués
Enfin c'est l'entrée que j'utilise
la source
Si vous utilisez formik dans votre projet, il a un moyen simple de gérer ce genre de choses. Voici la façon la plus simple de faire avec formik.
Définissez d'abord vos valeurs initiales dans l'attribut formik initivalues ou dans le react. Etat
Ici, les valeurs initiales sont définies en état réactif
définir ci-dessus initialValues pour le champ formik à l'intérieur de l'
initiValues
attribut formikCréez une console pour vérifier l'état mis à jour au
string
lieu deboolean
lasetFieldValue
fonction formik pour définir l'état ou utilisez l'outil de débogage React pour voir les changements dans les valeurs d'état formik.la source
essayez ce code:
la source
someProperty
et après l'exécution du code ci-dessus, seule laflag
propriété resteraj'ai vu ce qui suit dans un livre:
mais je ne sais pas si c'est vrai ..
la source