Pourquoi ne puis-je pas modifier directement un état du composant, vraiment?
Je comprends que Réagir la documentation et les tutoriels avertir dans des termes sans équivoque que l'état ne doit pas être directement muté et que tout doit passer par setState
.
J'aimerais comprendre pourquoi, exactement, je ne peux pas juste changer directement de l'état et ensuite (dans la même fonction) appel this.setState({})
juste pour déclencher la render
.
E. g.: Le code ci-dessous semble fonctionner parfaitement:
const React = require('react');
const App = React.createClass({
getInitialState: function() {
return {
some: {
rather: {
deeply: {
embedded: {
stuff: 1
}}}}};
},
updateCounter: function () {
this.state.some.rather.deeply.embedded.stuff++;
this.setState({}); //just to trigger the render ...
},
render: function() {
return (
<div>
Counter value: {this.state.some.rather.deeply.embedded.stuff}
<br></br>
<button onClick={this.updateCounter}>inc</button>
</div>
);
}
});
export default App;
Je suis tout de même pour les conventions suivantes, mais je voudrais améliorer mon mieux comprendre comment ReactJS fonctionne réellement et ce qui peut aller mal ou est-il sous-optimale avec le code ci-dessus.
Les notes sous le cette.setState
de la documentation essentiellement d'identifier les deux pièges:
- Que si vous muter état directement et appelez ensuite la
this.setState
cela peut remplacer (écraser?) la mutation que vous avez fait. Je ne vois pas comment cela peut arriver dans le code ci-dessus. - Que
setState
peut muterthis.state
efficacement dans un asynchrone /différé façon et donc, lors de l'accès àthis.state
droite après l'appel dethis.setState
vous ne sont pas garantis pour accéder à la finale muté de l'état. - Je que, par ce n'est pas un problème sithis.setState
est le dernier appel de la fonction de mise à jour.
- Consultez le notes sous
setState
de documentation. Il couvre certaines des bonnes raisons. - J'ai mis à jour ma question d'examiner également les notes que vous avez mentionné.
- a part le fait que vous pensez que vous avez le contrôle, vous êtes tout simplement en court-circuitant le cadre du flux de travail. Javascript permet de le faire, il suffit de garder à l'esprit qu'une fois que vous briser le modèle, le cadre n'est pas plus responsable de votre état de cohérence.
- Ce n'est pas une question de "ne peut" muter état directement, c'est une question de "ne devrait pas".
- Étrange, cela a été demandé il y a 4 mois et toujours pas de réponse, est-ce une question difficile à répondre ? Je ne peux pas vraiment trouver une réponse à cela à l'aide de google...
- J'ai posé une question similaire, stackoverflow.com/questions/40213254/...
- puis il devenir Anuglar1.
Vous devez vous connecter pour publier un commentaire.
La Réagir docs pour
setState
ont ceci à dire:En gros, si vous modifiez
this.state
directement, vous créez une situation où ces modifications peuvent être remplacées.Liés à votre étendu les questions 1) et 2),
setState()
n'est pas immédiate. Les files d'attente un état de transition basé sur ce qu'il pense qui se passe qui ne peut pas inclure la modification directe dethis.state
. Puisque c'est en file d'attente plutôt que de s'appliquer immédiatement, il est tout à fait possible que quelque chose est modifié entre de telles que votre modification directe écrasés.Si rien d'autre, vous pourriez être mieux de ne considérant que de ne pas modifier directement
this.state
peut être vu comme une bonne pratique. Vous savez peut-être personnellement à ce que votre code interagit avec Réagir de telle manière que ces écritures ou d'autres questions ne peuvent pas se produire, mais vous êtes en train de créer une situation où les autres développeurs ou les futures mises à jour peuvent soudainement se retrouver avec bizarre ou plus subtiles questions.setState()
et le rappel des systèmes de travail et vous donne une bonne idée de pourquoi il y aurait un problème.Cette réponse est de fournir suffisamment d'informations pour ne pas changer/la mutation de l'état directement à Réagir.
Réagir suit Unidirectionnel de Flux de Données. Sens, le flux de données à l'intérieur de réagir, et que ce sera attendu d'être sur une trajectoire circulaire.
Réagir de flux de Données, sans flux
Pour faire Réagir travail comme cela, les développeurs ont fait de l'Réagissent similaire à de la programmation fonctionnelle. La manette de la règle de la programmation fonctionnelle est immutabilité. Laissez-moi vous expliquer haut et fort.
Comment fonctionne le flux unidirectionnel de marche?
states
sont d'une banque de données qui contient les données d'un composant.view
d'un composant rend en fonction de l'état.view
besoin de changer quelque chose sur l'écran, que la valeur doit être fourni à partir de lastore
.setState()
fonction qui prend unobject
de nouveauxstates
et fait une comparaison et fusion(similaire àobject.assign()
) sur l'état précédent et ajoute le nouvel état à l'état banque de données.view
consomme et de l'afficher sur l'éboulis.Ce cycle continuera tout au long de la durée de vie du composant.
Si vous voyez les étapes ci-dessus, il montre clairement beaucoup de choses se passe derrière vous lorsque vous modifiez l'état. Donc, quand vous la mutation de l'état directement et appel
setState()
avec un objet vide. Leprevious state
sera polluée avec votre mutation. En raison de laquelle, les eaux peu profondes de comparaison et de fusion de deux états sera perturbé arriver ou ne pas arriver, parce que vous n'aurez qu'un état maintenant. Cela va perturber tout le Réagir du Cycle de vie des Méthodes.En conséquence, votre application va se comporter de manière anormale ou même tomber en panne. La plupart du temps, cela n'affectera pas votre application, car toutes les applications que nous utilisons pour tester cette sont assez petites.
Et un autre inconvénient de la mutation de
Objects
etArrays
en JavaScript est, lorsque vous affectez un objet ou un tableau, vous êtes juste de faire une référence de cet objet ou de ce tableau. Lorsque vous muter eux, toutes les références à cet objet ou de ce tableau seront touchés. Réagir gère cela dans une manière intelligente dans le fond et tout simplement de nous donner une API pour le faire fonctionner.Les erreurs les plus communes faites lors de la manipulation des états à réagir
Dans l'exemple ci-dessus,
this.state.a.push(6)
va muter l'état directement. En l'assignant à une autre variable et de l'appel desetState
est le même que ce qui est indiqué ci-dessous. Comme nous l'avons muté à l'état de toute façon, il n'y a aucun point de l'affecter à une variable et de l'appel desetState
avec cette variable.La plupart des gens ne ce. C'est si mal. Cela rompt la beauté de Réagir et il fera de vous un mauvais programmeur.
Alors, Quelle est la meilleure façon de traiter les états à réagir? Laissez-moi vous expliquer.
Lorsque vous avez besoin de changer "quelque chose" dans l'état actuel, de la première à obtenir une copie de ce "quelque chose" à partir de l'état actuel.
Maintenant, la mutation de
currentStateCopy
ne sera pas la mutation de l'état d'origine. Effectuer des opérations surcurrentStateCopy
et le définir comme le nouvel état à l'aide desetState()
C'est embellir droit?
En faisant cela, toutes les références de
this.state.a
de ne pas obtenir touchés jusqu'à ce que nous utilisonssetState
. Cela vous donne le contrôle sur votre code et ce sera vous aider à écrire élégant de tester et de vous faire confiance sur la performance du code en production.Pour répondre à votre question,
Oui, vous pouvez. Mais, vous avez besoin pour affronter les conséquences suivantes.
state
à travers des composants.Immutabilité n'est pas quelque chose de nécessaire, car le Javascript est mono-thread. Mais, Il est bon de suivre la pratique qui va vous aider dans le long terme.
PS. J'ai écrit au sujet de 10000 lignes de mutable Réagir code js. Si elle se casse maintenant, je ne sais pas où regarder, car toutes les valeurs sont mutés quelque part. Quand j'ai réalisé cela, j'ai commencé à écrire immuable code. Faites-moi confiance! C'est la meilleure chose que vous pouvez faire à un produit ou d'une application.
Espérons que cette aide!
slice
, ES6 déstructuration, etc.) sont peu profondes. Si vous avez un tableau imbriqué ou des objets imbriqués, vous aurez besoin d'examiner d'autres méthodes de profondeur de la copie, par exempleJSON.parse(JSON.stringify(obj))
(bien que cette méthode ne fonctionnera pas si votre objet a des références circulaires)._.cloneDeep
suffitnpm install lodash.clonedeep
et l'utiliser aveclet cloneDeep = require("lodash.clonedeep");
.la réponse la plus simple à "
est tout au sujet de la mise à Jour de phase.
quand on met à jour l'état d'un composant de tous les enfants vont être rendus ainsi. ou de l'ensemble de nos composants de l'arbre de rendu.
mais quand je dis que l'ensemble de notre composant de l'arbre est rendu cela ne signifie pas que la totalité du DOM est mis à jour.
lorsqu'un composant est rendu au fond, nous avons d'obtenir une réagir élément, de sorte que c'est la mise à jour de notre virtual dom.
Réagir examinerons ensuite le virtuel DOM, il a également une copie de l'ancien virtuel DOM, c'est pourquoi nous ne devrions pas mettre à jour l'état directement, de sorte que nous pouvons avoir deux différentes références de l'objet en mémoire, nous avons la vieille virtuel DOM ainsi que le nouveau virtual DOM.
alors réagir permettra de comprendre ce qui s'est changé et il mettra à jour la véritable DOM en conséquence .
espère que cela aide.
Ma compréhension actuelle est basée sur cette et cette réponse:
SI vous ne pas utiliser
shouldComponentUpdate
ou tout autre du cycle de vie des méthodes (commecomponentWillReceiveProps
,componentWillUpdate
, etcomponentDidUpdate
) lorsque vous comparez les anciens et les nouveaux accessoires/étatPUIS
ses beaux-à muter
state
et ensuite appelersetState()
, sinon c'est pas bien.