Préservation et réinitialisation de l'état
L'état est isolé entre les composants. React garde une trace de l'état appartenant à chaque composant en fonction de sa position dans l'arborescence de l'interface utilisateur. Vous pouvez contrôler quand préserver l'état et quand le réinitialiser entre les nouveaux rendus.
Vous allez apprendre
- Quand React choisit de préserver ou de réinitialiser l'état
- Comment forcer React à réinitialiser l'état d'un composant
- Comment les clés et les types affectent la préservation de l'état
L'état est lié à une position dans l'arbre de rendu
React construit desarbres de rendupour la structure des composants de votre interface utilisateur.
Lorsque vous donnez un état à un composant, vous pourriez penser que l'état « vit » à l'intérieur du composant. Mais l'état est en réalité détenu par React. React associe chaque morceau d'état qu'il détient au composant correct en fonction de l'endroit où ce composant se situe dans l'arbre de rendu.
Ici, il n'y a qu'une seule balise JSX<Counter />, mais elle est rendue à deux positions différentes :
Voici à quoi cela ressemble sous forme d'arbre :


Arbre React
Ce sont deux compteurs distincts car chacun est rendu à sa propre position dans l'arbre.Vous n'avez généralement pas besoin de penser à ces positions pour utiliser React, mais cela peut être utile de comprendre son fonctionnement.
Dans React, chaque composant à l'écran possède un état entièrement isolé. Par exemple, si vous affichez côte à côte deux composantsCounter, chacun d'eux aura ses propres étatsscoreethoverindépendants.
Essayez de cliquer sur les deux compteurs et remarquez qu'ils n'affectent pas l'autre :
Comme vous pouvez le voir, lorsqu'un compteur est mis à jour, seul l'état de ce composant est mis à jour :


Mise à jour de l'état
React gardera l'état tant que vous rendrez le même composant à la même position dans l'arbre. Pour le constater, incrémentez les deux compteurs, puis supprimez le deuxième composant en décochant la case « Afficher le deuxième compteur », puis ajoutez-le à nouveau en la cochant de nouveau :
Remarquez comment, au moment où vous arrêtez d'afficher le deuxième compteur, son état disparaît complètement. C'est parce que lorsque React supprime un composant, il détruit son état.


Suppression d'un composant
Lorsque vous cochez « Afficher le deuxième compteur », un deuxièmeCounteret son état sont initialisés à partir de zéro (score = 0) et ajoutés au DOM.


Ajout d'un composant
React préserve l'état d'un composant tant qu'il est rendu à sa position dans l'arbre d'interface utilisateur.S'il est supprimé, ou si un composant différent est rendu à la même position, React abandonne son état.
Le même composant à la même position préserve l'état
Dans cet exemple, il y a deux balises<Counter />différentes :
Lorsque vous cochez ou décochez la case, l'état du compteur n'est pas réinitialisé. QueisFancysoittrueoufalse, vous avez toujours un<Counter />comme premier enfant dudivretourné par le composant racineApp :


La mise à jour de l'état deAppne réinitialise pas leCountercar leCounterreste à la même position
C'est le même composant à la même position, donc du point de vue de React, c'est le même compteur.
Piège
Rappelez-vous quec'est la position dans l'arbre d'interface utilisateur—et non dans le balisage JSX—qui importe pour React !Ce composant a deux clausesreturnavec différentes balises<Counter />JSX à l'intérieur et à l'extérieur duif:
Vous pourriez vous attendre à ce que l'état soit réinitialisé lorsque vous cochez la case, mais ce n'est pas le cas ! C'est parce queces deux balises<Counter />sont rendues à la même position.React ne sait pas où vous placez les conditions dans votre fonction. Tout ce qu'il « voit », c'est l'arbre que vous retournez.
Dans les deux cas, le composantAppretourne un<div>avec<Counter />comme premier enfant. Pour React, ces deux compteurs ont la même « adresse » : le premier enfant du premier enfant de la racine. C'est ainsi que React les fait correspondre entre le rendu précédent et le suivant, quelle que soit la façon dont vous structurez votre logique.
Des composants différents à la même position réinitialisent l'état
Dans cet exemple, cocher la case remplacera<Counter>par un<p>:
Ici, vous basculez entredifférentstypes de composants à la même position. Initialement, le premier enfant du<div>contenait unCounter. Mais lorsque vous l'avez remplacé par unp, React a supprimé leCounterde l'arbre d'interface utilisateur et a détruit son état.


LorsqueCounterchange enp, leCounterest supprimé et lepest ajouté


Lors du retour, lepest supprimé et leCounterest ajouté
De plus,lorsque vous affichez un composant différent à la même position, cela réinitialise l'état de tout son sous-arbre.Pour voir comment cela fonctionne, incrémentez le compteur puis cochez la case :
L'état du compteur est réinitialisé lorsque vous cliquez sur la case à cocher. Bien que vous affichiez unCounter, le premier enfant dudivchange d'unsectionà undiv. Lorsque l'enfantsectiona été retiré du DOM, tout l'arbre en dessous (y compris leCounteret son état) a également été détruit.


Lorsquesectionchange endiv, lasectionest supprimée et le nouveaudivest ajouté


Lors du retour, ledivest supprimé et le nouveausectionest ajouté
En règle générale,si vous souhaitez préserver l'état entre les rendus, la structure de votre arbre doit « correspondre »d'un rendu à l'autre. Si la structure est différente, l'état est détruit car React détruit l'état lorsqu'il supprime un composant de l'arbre.
Piège
C'est pourquoi vous ne devriez pas imbriquer les définitions de fonctions de composant.
Ici, la fonction de composantMyTextFieldest définieà l'intérieurMyComponent:
Chaque fois que vous cliquez sur le bouton, l'état de l'entrée disparaît ! C'est parce qu'une fonctiondifférenteMyTextFieldest créée pour chaque rendu deMyComponent. Vous rendez un composantdifférentà la même position, donc React réinitialise tout l'état en dessous. Cela conduit à des bugs et des problèmes de performance. Pour éviter ce problème,déclarez toujours les fonctions de composant au niveau supérieur et n'imbriquez pas leurs définitions.
Réinitialiser l'état à la même position
Par défaut, React préserve l'état d'un composant tant qu'il reste à la même position. Généralement, c'est exactement ce que vous voulez, donc cela a du sens comme comportement par défaut. Mais parfois, vous pouvez vouloir réinitialiser l'état d'un composant. Considérez cette application qui permet à deux joueurs de suivre leurs scores pendant chaque tour :
Actuellement, lorsque vous changez de joueur, le score est préservé. Les deuxCounterapparaissent à la même position, donc React les voit commele mêmeCounterdont la proppersona changé.
Mais conceptuellement, dans cette application, ils devraient être deux compteurs distincts. Ils peuvent apparaître au même endroit dans l'interface utilisateur, mais l'un est un compteur pour Taylor, et l'autre est un compteur pour Sarah.
Il existe deux façons de réinitialiser l'état lors du passage de l'un à l'autre :
- Rendre les composants à des positions différentes
- Donner à chaque composant une identité explicite avec
key
Option 1 : Rendre un composant à des positions différentes
Si vous voulez que ces deuxCountersoient indépendants, vous pouvez les rendre à deux positions différentes :
- Initialement,
isPlayerAesttrue. Donc la première position contient l'état duCounter, et la seconde est vide. - Lorsque vous cliquez sur le bouton « Next player », la première position se vide mais la seconde contient maintenant un
Counter.


État initial


En cliquant sur « next »


En cliquant à nouveau sur « next »
L'état de chaqueCounterest détruit chaque fois qu'il est retiré du DOM. C'est pourquoi ils se réinitialisent à chaque fois que vous cliquez sur le bouton.
Cette solution est pratique lorsque vous n'avez que quelques composants indépendants rendus au même endroit. Dans cet exemple, vous n'en avez que deux, donc ce n'est pas un problème de les rendre séparément dans le JSX.
Option 2 : Réinitialiser l'état avec une clé
Il existe également une autre manière, plus générique, de réinitialiser l'état d'un composant.
Vous avez peut-être vu deskeys lors durendu de listes.Les clés ne sont pas seulement pour les listes ! Vous pouvez utiliser des clés pour que React distingue n'importe quels composants. Par défaut, React utilise l'ordre au sein du parent (« premier compteur », « second compteur ») pour différencier les composants. Mais les clés vous permettent de dire à React que ce n'est pas seulement unpremiercompteur, ou unsecondcompteur, mais un compteur spécifique—par exemple, le compteur deTaylor. Ainsi, React reconnaîtra le compteur deTayloroù qu'il apparaisse dans l'arbre !
Dans cet exemple, les deux<Counter />ne partagent pas d'état même s'ils apparaissent au même endroit dans le JSX :
Basculer entre Taylor et Sarah ne préserve pas l'état. C'est parce quevous leur avez donné deskeys différentes :
Spécifier unekeyindique à React d'utiliser lakeyelle-même comme faisant partie de la position, plutôt que leur ordre au sein du parent. C'est pourquoi, même si vous les rendez au même endroit dans le JSX, React les voit comme deux compteurs différents, et donc ils ne partageront jamais d'état. Chaque fois qu'un compteur apparaît à l'écran, son état est créé. Chaque fois qu'il est retiré, son état est détruit. Basculer entre eux réinitialise leur état encore et encore.
Remarque
Rappelez-vous que les clés ne sont pas globalement uniques. Elles spécifient uniquement la positionau sein du parent.
Réinitialiser un formulaire avec une clé
Réinitialiser l'état avec une clé est particulièrement utile lorsqu'on traite des formulaires.
Dans cette application de chat, le composant<Chat>contient l'état de la saisie de texte :
Essayez de saisir quelque chose dans le champ de saisie, puis cliquez sur « Alice » ou « Bob » pour choisir un autre destinataire. Vous remarquerez que l'état de la saisie est préservé car le<Chat>est rendu à la même position dans l'arbre.
Dans de nombreuses applications, ce comportement peut être souhaitable, mais pas dans une application de chat !Vous ne voulez pas que l'utilisateur envoie un message déjà saisi à la mauvaise personne à cause d'un clic accidentel. Pour corriger cela, ajoutez unekey:
Cela garantit que lorsque vous sélectionnez un destinataire différent, le composantChatsera recréé à partir de zéro, y compris tout état dans l'arbre situé en dessous. React recréera également les éléments DOM au lieu de les réutiliser.
Maintenant, le changement de destinataire efface toujours le champ de texte :
Récapitulatif
- React conserve l'état tant que le même composant est rendu à la même position.
- L'état n'est pas conservé dans les balises JSX. Il est associé à la position dans l'arbre où vous placez ce JSX.
- Vous pouvez forcer un sous-arbre à réinitialiser son état en lui donnant une clé différente.
- N'imbriquez pas les définitions de composants, sinon vous réinitialiserez l'état par accident.
Try out some challenges
Challenge 1 of 5:Fix disappearing input text #
This example shows a message when you press the button. However, pressing the button also accidentally resets the input. Why does this happen? Fix it so that pressing the button does not reset the input text.
