- Angenommen, ich habe eine React-Klasse P, die zwei untergeordnete Klassen, C1 und C2, rendert.
- C1 enthält ein Eingabefeld. Ich werde dieses Eingabefeld als Foo bezeichnen.
- Mein Ziel ist es, C2 auf Änderungen in Foo reagieren zu lassen.
Ich habe zwei Lösungen gefunden, aber keine davon fühlt sich ganz richtig an.
Erste Lösung:
- Weisen Sie P einen Zustand zu
state.input
. - Erstellen Sie eine
onChange
Funktion in P, die ein Ereignis aufnimmt und setztstate.input
. - Übergeben Sie dies
onChange
an C1 alsprops
und lassen Sie C1this.props.onChange
an dasonChange
von Foo binden .
Das funktioniert. Wenn sich der Wert von Foo ändert, wird a setState
in P ausgelöst, sodass P den Eingang hat, der an C2 übergeben werden kann.
Aber es fühlt sich aus dem gleichen Grund nicht ganz richtig an: Ich setze den Status eines übergeordneten Elements von einem untergeordneten Element aus. Dies scheint das Entwurfsprinzip von React zu verraten: Datenfluss in eine Richtung.
Soll ich das so machen oder gibt es eine reaktionsnatürlichere Lösung?
Zweite Lösung:
Setzen Sie einfach Foo in P.
Aber ist dies ein Entwurfsprinzip, dem ich bei der Strukturierung meiner App folgen sollte - indem ich alle Formularelemente in die render
Klasse der höchsten Ebene einsetze?
Wie in meinem Beispiel möchte ich, wenn ich ein großes Rendering von C1 habe, wirklich nicht das gesamte render
C1 auf render
P setzen, nur weil C1 ein Formularelement hat.
Wie soll ich das machen
Antworten:
Wenn ich Sie also richtig verstehe, schlägt Ihre erste Lösung vor, dass Sie den Status in Ihrer Stammkomponente beibehalten? Ich kann nicht für die Schöpfer von React sprechen, aber im Allgemeinen finde ich, dass dies eine richtige Lösung ist.
Die Aufrechterhaltung des Zustands ist einer der Gründe (zumindest denke ich), warum React erstellt wurde. Wenn Sie jemals eine eigene Client-Seite für Statusmuster implementiert haben, um mit einer dynamischen Benutzeroberfläche umzugehen, die viele voneinander abhängige bewegliche Elemente enthält, werden Sie React lieben, da dies viele dieser Probleme bei der Statusverwaltung lindert.
Wenn Sie den Status in der Hierarchie weiter oben halten und ihn durch Ereignisse aktualisieren, ist Ihr Datenfluss immer noch ziemlich unidirektional. Sie reagieren nur auf Ereignisse in der Root-Komponente. Sie erhalten die Daten dort nicht wirklich über eine bidirektionale Bindung. Sie teilen der Root-Komponente mit, dass "Hey, hier unten ist etwas passiert, überprüfen Sie die Werte", oder Sie übergeben den Status einiger Daten in der untergeordneten Komponente, um den Status zu aktualisieren. Sie haben den Status in C1 geändert und möchten, dass C2 darüber informiert wird. Durch Aktualisieren des Status in der Root-Komponente und erneutes Rendern sind die Requisiten von C2 jetzt synchron, da der Status in der Root-Komponente aktualisiert und weitergegeben wurde .
quelle
C2
eingetInitialState
für Daten und innerhalb derrender
es verwendetthis.state.data
?Nachdem ich jetzt mit React eine App erstellt habe, möchte ich einige Gedanken zu dieser Frage teilen, die ich vor einem halben Jahr gestellt habe.
Ich empfehle Ihnen zu lesen
Der erste Beitrag ist äußerst hilfreich, um zu verstehen, wie Sie Ihre React-App strukturieren sollten.
Flux beantwortet die Frage , warum Sie Ihre Reaktion App auf diese Weise strukturieren sollen (im Gegensatz zu , wie sie zu strukturieren). Die Reaktion macht nur 50% des Systems aus, und mit Flux können Sie das gesamte Bild sehen und sehen, wie sie ein kohärentes System bilden.
Zurück zur Frage.
Bei meiner ersten Lösung ist es völlig in Ordnung, den Handler in die umgekehrte Richtung gehen zu lassen , da die Daten immer noch in eine Richtung gehen.
Ob ein Handler einen setState in P auslösen lässt, kann jedoch je nach Ihrer Situation richtig oder falsch sein.
Wenn die App ein einfacher Markdown-Konverter ist, wobei C1 die Roheingabe und C2 die HTML-Ausgabe ist, ist es in Ordnung, C1 einen setState in P auslösen zu lassen, aber einige argumentieren möglicherweise, dass dies nicht die empfohlene Methode ist.
Wenn es sich bei der App jedoch um eine Aufgabenliste handelt, wobei C1 die Eingabe für die Erstellung einer neuen Aufgabe ist, C2 die Aufgabenliste in HTML, möchten Sie den Handler wahrscheinlich um zwei Ebenen höher als P - zu der
dispatcher
, mit der dasstore
Update durchgeführt werdendata store
kann. die dann die Daten an P senden und die Ansichten füllen. Siehe diesen Flux-Artikel. Hier ist ein Beispiel: Flux - TodoMVCIm Allgemeinen bevorzuge ich den im Beispiel der Aufgabenliste beschriebenen Weg. Je weniger Status Sie in Ihrer App haben, desto besser.
quelle
Die erste Lösung, bei der der Status in der übergeordneten Komponente beibehalten wird , ist die richtige . Bei komplexeren Problemen sollten Sie jedoch an eine State-Management-Bibliothek denken. Redux ist die beliebteste Bibliothek , die bei React verwendet wird.
quelle
Fünf Jahre später, mit der Einführung von React Hooks, gibt es jetzt eine viel elegantere Möglichkeit, dies mit useContext hook zu tun.
Sie definieren den Kontext in einem globalen Bereich, exportieren Variablen, Objekte und Funktionen in die übergeordnete Komponente und verpacken untergeordnete Elemente in der App in einen bereitgestellten Kontext und importieren alles, was Sie in untergeordneten Komponenten benötigen. Unten finden Sie einen Proof of Concept.
Sie können dieses Beispiel im Code Sandbox-Editor ausführen.
quelle
Ich bin überrascht, dass es im Moment, in dem ich schreibe, keine Antworten mit einer einfachen idiomatischen React-Lösung gibt. Also hier ist die eine (vergleiche die Größe und Komplexität mit anderen):
Jede kontrollierte
input
(idiomatische Art, mit Formularen in React zu arbeiten) aktualisiert den übergeordneten Status in seinemonChange
Rückruf und verrät immer noch nichts.Schauen Sie sich zum Beispiel die C1-Komponente genau an. Sehen Sie einen signifikanten Unterschied in der Art
C1
und Weise, wie eine integrierteinput
Komponente mit Statusänderungen umgeht? Das solltest du nicht, denn es gibt keine. Das Aufheben des Zustands und das Weitergeben von Wert / onChange-Paaren ist für Raw React idiomatisch. Keine Verwendung von Refs, wie einige Antworten vermuten lassen.quelle
this.state
, die Rückgabe fehlte beim Rendern, und mehrere Komponenten müssen in div oder so eingeschlossen sein. Ich weiß nicht, wie ich das verpasst habe, als ich die ursprüngliche Antwort geschrieben habe. Muss der Bearbeitungsfehler gewesen sein.Neuere Antwort mit einem Beispiel, das verwendet
React.useState
Es wird empfohlen, den Status in der übergeordneten Komponente beizubehalten. Das übergeordnete Element muss Zugriff darauf haben, da es über zwei untergeordnete Komponenten hinweg verwaltet wird. Das Verschieben in den globalen Status, wie der von Redux verwaltete, wird aus demselben Grund nicht empfohlen, aus dem die globale Variable im Software-Engineering im Allgemeinen schlechter ist als die lokale .
Wenn sich der Status in der übergeordneten Komponente befindet, kann das Kind ihn mutieren, wenn das übergeordnete Element dem Kind
value
und demonChange
Handler Requisiten gibt (manchmal wird es als Wertverknüpfung oder Statusverknüpfungsmuster bezeichnet). So würden Sie es mit Haken machen:Die gesamte übergeordnete Komponente wird bei einer Eingabeänderung im untergeordneten Element erneut gerendert. Dies ist möglicherweise kein Problem, wenn die übergeordnete Komponente klein / schnell neu zu rendern ist. Die Leistung beim erneuten Rendern der übergeordneten Komponente kann im allgemeinen Fall weiterhin ein Problem sein (z. B. große Formulare). Dies ist das Problem in Ihrem Fall gelöst (siehe unten).
Das Statusverknüpfungsmuster und kein übergeordnetes erneutes Rendern lassen sich mithilfe der Drittanbieter-Bibliothek wie Hookstate einfacher implementieren - aufgeladen
React.useState
, um eine Vielzahl von Anwendungsfällen abzudecken, einschließlich Ihres. (Haftungsausschluss: Ich bin Autor des Projekts).So würde es mit Hookstate aussehen.
Child1
wird die Eingabe ändern,Child2
wird darauf reagieren.Parent
hält den Status, wird aber nur bei Statusänderung nicht erneut gerendertChild1
undChild2
wird.PS: Es gibt hier viele weitere Beispiele für ähnliche und kompliziertere Szenarien, einschließlich tief verschachtelter Daten, Statusvalidierung, globaler Status mit
setState
Hook usw. Es gibt auch eine vollständige Online-Beispielanwendung , die den Hookstate und die oben erläuterte Technik verwendet.quelle
Sie sollten die Redux- und ReactRedux-Bibliothek kennenlernen. Sie strukturiert Ihre Status und Requisiten in einem Geschäft und Sie können später in Ihren Komponenten darauf zugreifen.
quelle
Mit React> = 16.3 können Sie ref und forwardRef verwenden, um vom übergeordneten Element auf das DOM des Kindes zuzugreifen. Verwenden Sie keine alten Refs mehr.
Hier ist das Beispiel anhand Ihres Falls:
Siehe Refs und ForwardRef für detaillierte Informationen über Refs und forwardRef.
quelle
shouldComponentUpdate(nextProps, nextState)
Der folgende Code verwendet
@bound
Anmerkungen aus ES.Nextbabel-plugin-transform-decorators-legacy
von BabelJS 6 und Klasseneigenschaften (die Anmerkung legt diesen Wert für Elementfunktionen fest , die bind ähneln):quelle
Das Konzept der Weitergabe von Daten vom Elternteil an das Kind und umgekehrt wird erläutert.
quelle