- Supposons que j'ai une classe React P, qui rend deux classes enfants, C1 et C2.
- C1 contient un champ de saisie. Je ferai référence à ce champ de saisie comme Foo.
- Mon objectif est de laisser C2 réagir aux changements de Foo.
J'ai trouvé deux solutions, mais aucune d'elles ne semble tout à fait correcte.
Première solution:
- Assigner un état P,
state.input
. - Créez une
onChange
fonction dans P, qui prend un événement et définitstate.input
. - Passez ceci
onChange
à C1 en tant que aprops
, et laissez C1 se lierthis.props.onChange
auonChange
de Foo.
Cela marche. Chaque fois que la valeur de Foo change, il déclenche a setState
dans P, donc P aura l'entrée pour passer à C2.
Mais cela ne me semble pas tout à fait correct pour la même raison: je définis l'état d'un élément parent à partir d'un élément enfant. Cela semble trahir le principe de conception de React: un flux de données unidirectionnel.
Est-ce ainsi que je suis censé le faire, ou y a-t-il une solution plus naturelle de React?
Deuxième solution:
Mettez simplement Foo dans P.
Mais est-ce un principe de conception que je devrais suivre lorsque je structure mon application, en plaçant tous les éléments du formulaire dans la render
classe de niveau le plus élevé?
Comme dans mon exemple, si j'ai un grand rendu de C1, je ne veux vraiment pas mettre l'ensemble render
de C1 à render
de P simplement parce que C1 a un élément de formulaire.
Comment dois-je le faire?
Réponses:
Donc, si je vous comprends bien, votre première solution suggère que vous gardiez l'état dans votre composant racine? Je ne peux pas parler au nom des créateurs de React, mais en général, je trouve que c'est une bonne solution.
Le maintien de l'état est l'une des raisons (du moins je pense) pour lesquelles React a été créé. Si vous avez déjà implémenté votre propre modèle d'état côté client pour gérer une interface utilisateur dynamique qui a beaucoup de pièces mobiles interdépendantes, alors vous adorerez React, car cela atténue beaucoup de ces problèmes de gestion d'état.
En gardant l'état plus haut dans la hiérarchie et en le mettant à jour via des événements, votre flux de données est toujours à peu près unidirectionnel, vous répondez simplement aux événements dans le composant racine, vous n'obtenez pas vraiment les données via une liaison bidirectionnelle, vous dites au composant racine que "hé, quelque chose s'est passé ici, vérifiez les valeurs" ou vous transmettez l'état de certaines données dans le composant enfant afin de mettre à jour l'état. Vous avez changé l'état dans C1 et vous voulez que C2 en soit conscient, donc, en mettant à jour l'état dans le composant racine et en effectuant un nouveau rendu, les accessoires de C2 sont maintenant synchronisés depuis que l'état a été mis à jour dans le composant racine et transmis .
la source
C2
avez ungetInitialState
pour les données etrender
qu'il utilisethis.state.data
?Ayant utilisé React pour créer une application maintenant, j'aimerais partager quelques réflexions sur cette question que j'ai posée il y a six mois.
Je vous recommande de lire
Le premier article est extrêmement utile pour comprendre comment vous devez structurer votre application React.
Flux répond à la question de savoir pourquoi devriez-vous structurer votre application React de cette manière (par opposition à la façon de la structurer). React ne représente que 50% du système, et avec Flux, vous obtenez une vue d'ensemble et voyez comment ils constituent un système cohérent.
Revenons à la question.
Quant à ma première solution, il est tout à fait normal de laisser le gestionnaire aller dans le sens inverse, car les données vont toujours dans un seul sens.
Cependant, le fait de laisser un gestionnaire déclencher un setState dans P peut être correct ou incorrect selon votre situation.
Si l'application est un simple convertisseur Markdown, C1 étant l'entrée brute et C2 la sortie HTML, vous pouvez laisser C1 déclencher un setState dans P, mais certains pourraient dire que ce n'est pas la manière recommandée de le faire.
Cependant, si l'application est une liste de tâches, C1 étant l'entrée pour créer une nouvelle tâche, C2 la liste de tâches en HTML, vous voulez probablement que le gestionnaire monte de deux niveaux par rapport à P - vers le
dispatcher
, ce qui permet destore
mettre à jour ledata store
, qui envoient ensuite les données à P et remplissent les vues. Voir cet article Flux. Voici un exemple: Flux - TodoMVCEn général, je préfère la manière décrite dans l'exemple de liste de tâches. Moins vous avez d'état dans votre application, mieux c'est.
la source
Cinq ans plus tard, avec l'introduction de React Hooks, il existe maintenant une manière beaucoup plus élégante de le faire avec useContext hook.
Vous définissez le contexte dans une portée globale, exportez des variables, des objets et des fonctions dans le composant parent, puis enveloppez les enfants dans l'application dans un contexte fourni et importez tout ce dont vous avez besoin dans les composants enfants. Voici une preuve de concept.
Vous pouvez exécuter cet exemple dans l'éditeur Code Sandbox.
la source
La première solution, avec le maintien de l'état dans le composant parent , est la bonne . Cependant, pour des problèmes plus complexes, vous devriez penser à une bibliothèque de gestion d'état , redux est la plus utilisée avec react.
la source
Je suis surpris qu'il n'y ait pas de réponses avec une solution React idiomatique simple au moment où j'écris. Alors, voici celui (comparez la taille et la complexité aux autres):
Toute méthode contrôlée
input
(manière idiomatique de travailler avec les formulaires dans React) met à jour l'état parent dans sononChange
rappel et ne trahit toujours rien.Regardez attentivement le composant C1, par exemple. Voyez-vous une différence significative dans la manière dont le composant
C1
intégréinput
gère les changements d'état? Vous ne devriez pas, car il n'y en a pas. Lever l'état et transmettre des paires valeur / onChange est idiomatique pour Raw React. Pas d'utilisation de références, comme le suggèrent certaines réponses.la source
this.state
, le retour était manquant dans le rendu et plusieurs composants doivent être enveloppés dans div ou quelque chose. Je ne sais pas comment j'ai manqué ça quand j'ai écrit la réponse originale. Doit avoir été l'erreur d'édition.Réponse plus récente avec un exemple, qui utilise
React.useState
Il est recommandé de conserver l'état dans le composant parent. Le parent doit y avoir accès car il le gère sur deux composants enfants. Le déplacer vers l'état global, comme celui géré par Redux, n'est pas recommandé pour la même raison que la variable globale est pire que locale en général en génie logiciel.
Lorsque l'état est dans le composant parent, l'enfant peut le muter si le parent donne l'enfant
value
et leonChange
gestionnaire dans les accessoires (parfois, il est appelé lien de valeur ou modèle de lien d'état ). Voici comment vous le feriez avec des crochets:L'ensemble du composant parent sera rendu lors de la modification d'entrée dans l'enfant, ce qui peut ne pas poser de problème si le composant parent est petit / rapide à restituer. Les performances de re-rendu du composant parent peuvent toujours être un problème dans le cas général (par exemple les grands formulaires). Ce problème est résolu dans votre cas (voir ci-dessous).
Le modèle de lien d'état et l' absence de rendu du parent sont plus faciles à implémenter en utilisant la bibliothèque tierce, comme Hookstate - suralimenté
React.useState
pour couvrir une variété de cas d'utilisation, y compris le vôtre. (Avertissement: je suis un auteur du projet).Voici à quoi cela ressemblerait avec Hookstate.
Child1
changera l'entrée,Child2
y réagira.Parent
conservera l'état mais ne sera pas restitué lors du changement d'état, seulementChild1
et leChild2
fera.PS: il y a beaucoup plus d'exemples ici couvrant des scénarios similaires et plus compliqués, y compris des données profondément imbriquées, la validation d'état, l'état global avec
setState
hook, etc. Il existe également un exemple d'application complet en ligne , qui utilise le Hookstate et la technique expliquée ci-dessus.la source
Vous devriez apprendre la bibliothèque Redux et ReactRedux, elle structurera vos états et accessoires dans un seul magasin et vous pourrez y accéder plus tard dans vos composants.
la source
Avec React> = 16.3, vous pouvez utiliser ref et forwardRef, pour accéder au DOM de l'enfant depuis son parent. N'utilisez plus l'ancienne méthode de référence.
Voici l'exemple utilisant votre cas:
Voir Réfs et ForwardRef pour des informations détaillées sur refs et forwardRef.
la source
shouldComponentUpdate(nextProps, nextState)
Le code ci-dessous utilise les
@bound
annotations de ES.Nextbabel-plugin-transform-decorators-legacy
de BabelJS 6 et class-properties (l'annotation définit cette valeur sur les fonctions membres similaires à bind):la source
Le concept de transmission de données du parent à l'enfant et vice versa est expliqué.
la source