Ich habe gerade mit ReactJS angefangen und bin ein wenig auf ein Problem fixiert, das ich habe.
Meine Anwendung ist im Wesentlichen eine Liste mit Filtern und einer Schaltfläche zum Ändern des Layouts. Im Moment bin ich mit drei Komponenten: <list />
, < Filters />
und <TopBar />
, nun offensichtlich , wenn ich die Einstellungen ändern in < Filters />
ich eine Methode zur Auslösung in wollen <list />
aktualisieren meine Ansicht.
Wie kann ich diese drei Komponenten miteinander interagieren lassen oder benötige ich ein globales Datenmodell, an dem ich nur Änderungen vornehmen kann?
javascript
reactjs
woutr_be
quelle
quelle
Antworten:
Der beste Ansatz hängt davon ab, wie Sie diese Komponenten anordnen möchten. Einige Beispielszenarien, die mir gerade in den Sinn kommen:
<Filters />
ist eine untergeordnete Komponente von<List />
<Filters />
und<List />
sind untergeordnete Elemente einer übergeordneten Komponente<Filters />
und<List />
leben in separaten Wurzelkomponenten vollständig.Es kann andere Szenarien geben, an die ich nicht denke. Wenn deins nicht in diese passt, dann lass es mich wissen. Hier sind einige sehr grobe Beispiele dafür, wie ich mit den ersten beiden Szenarien umgegangen bin:
Szenario 1
Sie können einen Handler von
<List />
bis übergeben<Filters />
, der dann für dasonChange
Ereignis aufgerufen werden kann , um die Liste mit dem aktuellen Wert zu filtern.JSFiddle für # 1 →
Szenario 2
Ähnlich wie in Szenario 1, jedoch wird die übergeordnete Komponente die Handlerfunktion an übergeben
<Filters />
und die gefilterte Liste an übergeben<List />
. Ich mag diese Methode besser, da sie die<List />
von der entkoppelt<Filters />
.JSFiddle für # 2 →
Szenario 3
Wenn die Komponenten nicht zwischen Eltern-Kind-Beziehungen kommunizieren können, wird in der Dokumentation empfohlen, ein globales Ereignissystem einzurichten .
quelle
updateFilter
in<Filters />
Bezug auf und ein Arrayitems
in Bezug auf<List />
. Sie können diese untergeordneten Komponenten in anderen Eltern mit unterschiedlichen Verhaltensweisen verwenden, entweder zusammen oder alleine. Zum Beispiel, wenn Sie eine dynamische Liste anzeigen möchten, aber keine Filterung benötigen.Es gibt mehrere Möglichkeiten, Komponenten zur Kommunikation zu bringen. Einige können für Ihren Anwendungsfall geeignet sein. Hier ist eine Liste von einigen, die ich als nützlich erachtet habe.
Reagieren
Direkte Kommunikation zwischen Eltern und Kind
Hier ruft die untergeordnete Komponente einen vom übergeordneten Element bereitgestellten Rückruf mit einem Wert auf, und das übergeordnete Element kann den von den untergeordneten Elementen im übergeordneten Element bereitgestellten Wert abrufen.
Wenn Sie eine Funktion / Seite Ihrer App erstellen, ist es besser, wenn ein einzelner Elternteil die Rückrufe / den Status (auch
container
oder genanntsmart component
) verwaltet und alle Kinder zustandslos sind und nur dem Elternteil Bericht erstatten. Auf diese Weise können Sie den Status des Elternteils problemlos an jedes Kind weitergeben, das ihn benötigt.Kontext
Mit React Context können Sie den Status an der Wurzel Ihrer Komponentenhierarchie halten und diesen Status problemlos in sehr tief verschachtelte Komponenten einfügen, ohne dass Sie Requisiten an alle Zwischenkomponenten weitergeben müssen.
Bisher war der Kontext eine experimentelle Funktion, aber in React 16.3 ist eine neue API verfügbar.
Der Verbraucher nutzt die render prop / children
Überprüfen Sie diesen Blog-Beitrag für weitere Details.
Vor React 16.3 würde ich die Verwendung von React -Broadcast empfehlen, die eine ziemlich ähnliche API bieten, und die frühere Kontext-API verwenden.
Portale
Verwenden Sie ein Portal, wenn Sie zwei Komponenten nahe beieinander halten möchten, damit sie mit einfachen Funktionen kommunizieren können, wie dies bei normalen Eltern / Kindern der Fall ist. Sie möchten jedoch nicht, dass diese beiden Komponenten eine Eltern / Kind-Beziehung im DOM haben, da der damit verbundenen visuellen / CSS-Einschränkungen (wie Z-Index, Deckkraft ...).
In diesem Fall können Sie ein "Portal" verwenden. Es gibt verschiedene Reaktionsbibliotheken mit Portalen , die normalerweise für Modale , Popups, Tooltips ... verwendet werden.
Folgendes berücksichtigen:
Könnte beim Rendern im Inneren das folgende DOM erzeugen
reactAppContainer
:Weitere Details hier
Schlüssel
Sie definieren irgendwo einen Slot und füllen den Slot dann an einer anderen Stelle Ihres Renderbaums.
Dies ist Portalen etwas ähnlich, außer dass der gefüllte Inhalt in einem von Ihnen definierten Slot gerendert wird, während Portale im Allgemeinen einen neuen Dom-Knoten rendern (häufig untergeordnete Elemente von document.body).
Überprüfen Sie die React-Slot-Fill- Bibliothek
Ereignisbus
Wie in der React- Dokumentation angegeben :
Es gibt viele Dinge, mit denen Sie einen Ereignisbus einrichten können. Sie können einfach ein Array von Listenern erstellen. Bei der Veröffentlichung eines Ereignisses erhalten alle Listener das Ereignis. Oder Sie können etwas wie EventEmitter oder PostalJs verwenden
Fluss
Flux ist im Grunde ein Ereignisbus, außer dass die Ereignisempfänger Geschäfte sind. Dies ähnelt dem grundlegenden Ereignisbussystem, außer dass der Status außerhalb von React verwaltet wird
Die ursprüngliche Flux-Implementierung scheint ein Versuch zu sein, Event-Sourcing auf hackige Weise durchzuführen.
Redux ist für mich die Flux-Implementierung, die der Event-Beschaffung am nächsten kommt. Sie bietet viele Vorteile der Event-Beschaffung, z. B. die Möglichkeit, Zeitreisen zu unternehmen. Es ist nicht eng mit React verknüpft und kann auch mit anderen funktionalen Ansichtsbibliotheken verwendet werden.
Das Redux- Video-Tutorial von Egghead ist wirklich nett und erklärt, wie es intern funktioniert (es ist wirklich einfach).
Cursor
Cursor kommen aus ClojureScript / Om und werden häufig in React-Projekten verwendet. Sie ermöglichen die Verwaltung des Status außerhalb von React und ermöglichen mehreren Komponenten Lese- / Schreibzugriff auf denselben Teil des Status, ohne dass Sie etwas über den Komponentenbaum wissen müssen.
Es gibt viele Implementierungen, einschließlich ImmutableJS , React-Cursors und Omniscient
Edit 2016 : Es scheint, dass die Leute der Meinung sind, dass Cursor für kleinere Apps gut funktionieren, aber für komplexe Apps nicht gut skalierbar sind. Om Next hat keine Cursor mehr (während Om das Konzept ursprünglich eingeführt hat)
Ulmenarchitektur
Die Elm-Architektur ist eine Architektur, die von der Elm-Sprache verwendet werden soll . Auch wenn Elm nicht ReactJS ist, kann die Elm-Architektur auch in React ausgeführt werden.
Dan Abramov, der Autor von Redux, hat eine Implementierung der Elm-Architektur mit React durchgeführt.
Sowohl Redux als auch Elm sind wirklich großartig und tendieren dazu, Event-Sourcing-Konzepte im Frontend zu unterstützen. Beide ermöglichen das Debuggen von Zeitreisen, das Rückgängigmachen / Wiederherstellen, die Wiedergabe ...
Der Hauptunterschied zwischen Redux und Elm besteht darin, dass Elm in Bezug auf das staatliche Management tendenziell viel strenger ist. In Elm können keine lokalen Komponentenstatus- oder Mount / Unmount-Hooks vorhanden sein, und alle DOM-Änderungen müssen durch globale Statusänderungen ausgelöst werden. Die Elm-Architektur schlägt einen skalierbaren Ansatz vor, mit dem der gesamte Status innerhalb eines einzelnen unveränderlichen Objekts verarbeitet werden kann, während Redux einen Ansatz vorschlägt, mit dem Sie aufgefordert werden, den größten Teil des Status in einem einzelnen unveränderlichen Objekt zu verarbeiten.
Während das konzeptionelle Modell von Elm sehr elegant ist und die Architektur eine gute Skalierung auf großen Apps ermöglicht, kann es in der Praxis schwierig sein oder mehr Boilerplate erfordern, um einfache Aufgaben wie das Fokussieren auf eine Eingabe nach dem Mounten oder das Integrieren in eine vorhandene Bibliothek zu erledigen mit einer zwingenden Schnittstelle (dh JQuery-Plugin). Verwandte Ausgabe .
Außerdem beinhaltet die Elm-Architektur mehr Code-Boilerplate. Es ist nicht so ausführlich oder kompliziert zu schreiben, aber ich denke, die Elm-Architektur eignet sich eher für statisch typisierte Sprachen.
FRP
Bibliotheken wie RxJS, BaconJS oder Kefir können verwendet werden, um FRP-Streams für die Kommunikation zwischen Komponenten zu erstellen.
Sie können zum Beispiel Rx-React ausprobieren
Ich denke, die Verwendung dieser Bibliotheken ähnelt der Verwendung der ELM-Sprache mit Signalen .
Das CycleJS- Framework verwendet nicht ReactJS, sondern vdom . Es hat viele Ähnlichkeiten mit der Elm-Architektur (ist aber im wirklichen Leben einfacher zu verwenden, da es Vdom-Hooks zulässt) und verwendet RxJs häufig anstelle von Funktionen. Es kann eine gute Inspirationsquelle sein, wenn Sie FRP verwenden möchten Reagieren. CycleJs Egghead-Videos sind gut zu verstehen, wie es funktioniert.
CSP
CSP (Communicating Sequential Processes) sind derzeit beliebt (hauptsächlich wegen Go / goroutines und core.async / ClojureScript), aber Sie können sie auch in Javascript mit JS-CSP verwenden .
James Long hat ein Video gemacht, in dem erklärt wird, wie es mit React verwendet werden kann.
Sagas
Eine Saga ist ein Backend-Konzept, das aus der DDD / EventSourcing / CQRS-Welt stammt und auch als "Prozessmanager" bezeichnet wird. Es wird vom Redux-Saga- Projekt populär gemacht , hauptsächlich als Ersatz für Redux-Thunk zur Behandlung von Nebenwirkungen (dh API-Aufrufe usw.). Die meisten Leute denken derzeit, dass es nur um Nebenwirkungen geht, aber es geht eigentlich mehr darum, Komponenten zu entkoppeln.
Es ist eher ein Kompliment an eine Flux-Architektur (oder Redux) als an ein völlig neues Kommunikationssystem, da die Saga am Ende Flux-Aktionen ausgibt. Die Idee ist, dass Sie, wenn Sie Widget1 und Widget2 haben und möchten, dass sie entkoppelt werden, keine Aktion auslösen können, die auf Widget2 von Widget1 abzielt. Sie lassen also Widget1 nur Aktionen abfeuern, die auf sich selbst abzielen, und die Saga ist ein "Hintergrundprozess", der auf Widget1-Aktionen wartet und möglicherweise Aktionen auslöst, die auf Widget2 abzielen. Die Saga ist der Kopplungspunkt zwischen den beiden Widgets, aber die Widgets bleiben entkoppelt.
Wenn Sie interessiert sind, schauen Sie sich meine Antwort hier an
Fazit
Wenn Sie ein Beispiel derselben kleinen App mit diesen verschiedenen Stilen sehen möchten, überprüfen Sie die Zweige dieses Repositorys .
Ich weiß nicht, was auf lange Sicht die beste Option ist, aber ich mag es wirklich, wie Flux wie Event-Sourcing aussieht.
Wenn Sie keine Event-Sourcing-Konzepte kennen, werfen Sie einen Blick auf diesen sehr pädagogischen Blog: Wenn Sie die Datenbank mit Apache Samza auf den Kopf stellen , ist es ein Muss zu verstehen, warum Flux nett ist (dies könnte jedoch auch für FRP gelten )
Ich denke, die Community ist sich einig, dass die vielversprechendste Flux-Implementierung Redux ist , die dank Hot-Reloading nach und nach eine sehr produktive Entwicklererfahrung ermöglicht. Beeindruckende Live-Codierung von Bret Victors Video " Inventing on Principle" ist möglich!
quelle
OK, es gibt nur wenige Möglichkeiten, dies zu tun, aber ich möchte mich ausschließlich auf die Verwendung von Store mit Redux konzentrieren , was Ihnen das Leben in diesen Situationen erheblich erleichtert, anstatt Ihnen nur für diesen Fall eine schnelle Lösung zu bieten wirklich große Anwendung und Kommunikation zwischen Komponenten wird immer schwieriger, je größer die Anwendung wird ...
Also was Redux für Sie?
Redux ist wie ein lokaler Speicher in Ihrer Anwendung, der verwendet werden kann, wenn Daten an verschiedenen Stellen in Ihrer Anwendung verwendet werden müssen ...
Grundsätzlich stammt die Redux-Idee ursprünglich aus dem Fluss, aber mit einigen grundlegenden Änderungen, einschließlich des Konzepts, eine Quelle der Wahrheit zu haben, indem nur ein Geschäft erstellt wird ...
Schauen Sie sich die Grafik unten an, um einige Unterschiede zwischen Flux und Redux zu sehen ...
Ziehen Sie in Betracht, Redux anzuwenden in von Anfang an in Ihrer Anwendung wenn Ihre Anwendung eine Kommunikation zwischen Komponenten benötigt ...
Das Lesen dieser Wörter aus der Redux-Dokumentation kann zunächst hilfreich sein:
quelle
datepicker
(als Komponente) habe und diese Komponente von mehreren Komponenten auf derselben Seite geladen werden kann, woherdatepicker
weiß die Komponente dann, welche Aktion an redux gesendet werden soll? Dies ist die Essenz des Problems, eine Aktion in einer Komponente mit einer anderen und NICHT mit einer anderen Komponente zu verknüpfen . (Berücksichtigen Sie, dass dasdatepicker
redux
und was Sie speichern können, aber WIE die Aktion tief passieren , was es braucht auszulösen. Woher weiß eine tiefe Komponente, was GENAU ausgelöst werden muss? Da ich im Beispiel eine allgemeine Komponente angegeben habe, die je nach Szenario einen bestimmten Reduzierer auslösen sollte, kann es sich also um einen anderen Reduzierer handeln, da für jede Komponente ein Datepicker- Modal verwendet werden kann.So habe ich damit umgegangen.
Angenommen, Sie haben eine <Auswahl> für Monat und eine <Auswahl> für Tag . Die Anzahl der Tage hängt vom ausgewählten Monat ab.
Beide Listen gehören einem dritten Objekt, dem linken Bereich. Beide <select> sind auch untergeordnete Elemente des leftPanel <div>.
Es ist ein Spiel mit den Rückrufen und den Handlern in der LeftPanel- Komponente.
Um es zu testen, kopieren Sie einfach den Code in zwei getrennte Dateien und führen Sie die index.html aus . Wählen Sie dann einen Monat aus und sehen Sie, wie sich die Anzahl der Tage ändert.
Termine.js
Und der HTML- Code zum Ausführen der linken Indexkomponente index.html
quelle
Ich habe gesehen, dass die Frage bereits beantwortet ist, aber wenn Sie mehr Details erfahren möchten, gibt es insgesamt 3 Fälle von Kommunikation zwischen Komponenten :
quelle
In der Dokumentation wird empfohlen, ein globales Ereignissystem einzurichten, um die Antwort von @MichaelLaCroix zu erweitern, wenn in einem Szenario die Komponenten nicht zwischen Eltern-Kind-Beziehungen kommunizieren können.
Im Fall von
<Filters />
und<TopBar />
ohne eine der oben genannten Beziehungen könnte ein einfacher globaler Emitter wie folgt verwendet werden:componentDidMount
- Abonnieren Sie die VeranstaltungcomponentWillUnmount
- Abmeldung vom EventReact.js und EventSystem-Code
EventSystem.js
NotificationComponent.js
quelle
Es gibt eine solche Möglichkeit, auch wenn es sich nicht um eine Eltern-Kind-Beziehung handelt - und das ist Flux. Es gibt eine ziemlich gute (für mich persönlich) Implementierung für Alt.JS (mit Alt-Container).
Beispielsweise können Sie eine Seitenleiste haben, die davon abhängt, was in den Komponentendetails festgelegt ist. Die Komponenten-Seitenleiste ist mit SidebarActions und SidebarStore verbunden, während Details DetailsActions und DetailsStore sind.
Sie könnten dann AltContainer so verwenden
Welches würde Geschäfte halten (nun, ich könnte "Geschäft" anstelle von "Geschäfte" Requisite verwenden). Jetzt kann {this.props.content} Details sein, abhängig von der Route. Nehmen wir an, dass / Details uns zu dieser Ansicht weiterleiten. Details hätten zum Beispiel ein Kontrollkästchen, das das Seitenleistenelement von X in Y ändern würde, wenn es aktiviert wäre.
Technisch gibt es keine Beziehung zwischen ihnen und es wäre schwierig, ohne Fluss auszukommen. ABER damit ist es ziemlich einfach.
Kommen wir nun zu DetailsActions. Wir werden dort schaffen
und DetailsStore
Und jetzt ist dies der Ort, an dem Magie beginnt.
Wie Sie sehen, gibt es bindListener für SidebarActions.ComponentStatusChanged, das verwendet wird, wenn setSiteComponent verwendet wird.
jetzt in SidebarActions
Wir haben so etwas. Das Objekt wird auf Abruf versendet. Und es wird aufgerufen, ob setSiteComponent im Store verwendet wird (das Sie in component beispielsweise während onChange on Button oder was auch immer verwenden können).
Jetzt im SidebarStore haben wir
Jetzt können Sie hier sehen, dass es auf DetailsStore wartet. Was bedeutet das? Mehr oder weniger bedeutet dies, dass diese Methode auf das Update von DetailsStoreto warten muss, bevor sie sich selbst aktualisieren kann.
One Store überwacht Methoden in einem Store und löst eine Aktion aus der Komponentenaktion aus, die seinen eigenen Store aktualisiert.
Ich hoffe es kann dir irgendwie helfen.
quelle
Wenn Sie Möglichkeiten der Kommunikation zwischen Komponenten erkunden möchten und das Gefühl haben, dass es immer schwieriger wird, sollten Sie ein gutes Entwurfsmuster anwenden: Flux .
Es ist einfach eine Sammlung von Regeln, die definieren, wie Sie den anwendungsweiten Status speichern und mutieren und diesen Status zum Rendern von Komponenten verwenden.
Es gibt viele Flux-Implementierungen, und die offizielle Implementierung von Facebook ist eine davon. Es wird zwar als das angesehen, das den meisten Boilerplate-Code enthält, aber es ist leichter zu verstehen, da die meisten Dinge explizit sind.
Einige andere Alternativen sind Flummox Fluxxor Fluxible und Redux .
quelle
Ich war einmal dort, wo Sie gerade sind. Als Anfänger fühlen Sie sich manchmal fehl am Platz, wie Sie darauf reagieren. Ich werde versuchen, genauso vorzugehen, wie ich es mir gerade vorstelle.
Staaten sind der Eckpfeiler für die Kommunikation
Normalerweise kommt es darauf an, wie Sie die Zustände in dieser Komponente ändern, in Ihrem Fall weisen Sie auf drei Komponenten hin.
<List />
: In Abhängigkeit von einem Filter wird wahrscheinlich eine Liste mit Elementen angezeigt<Filters />
: Filteroptionen, die Ihre Daten ändern.<TopBar />
: Liste der Optionen.Um all diese Interaktionen zu orchestrieren, benötigen Sie eine höhere Komponente. Nennen wir sie App, die Aktionen und Daten an jede dieser Komponenten weitergibt, damit sie beispielsweise so aussehen können
Wenn
setFilter
es aufgerufen wird, wirkt es sich auf das gefilterte Element aus und rendert beide Komponenten neu. Falls dies nicht ganz klar ist, habe ich Ihnen ein Beispiel mit Kontrollkästchen gemacht, das Sie in einer einzelnen Datei einchecken können:quelle
Der folgende Code hilft mir beim Einrichten der Kommunikation zwischen zwei Geschwistern. Das Setup wird in ihrem übergeordneten Element während der Aufrufe von render () und componentDidMount () durchgeführt. Es basiert auf https://reactjs.org/docs/refs-and-the-dom.html Ich hoffe, es hilft.
quelle
Seltsamerweise erwähnte niemand
mobx
. Die Idee ist ähnlich wieredux
. Wenn ich Daten habe, die von mehreren Komponenten abonniert wurden, kann ich diese Daten verwenden, um mehrere Komponenten zu steuern.quelle