Erste Schritte mit der Flux-Architektur als Reaktion

Was Sie erstellen werden

In diesem Lernprogramm erfahren Sie mehr über die Flux-Architektur von Facebook und darüber, wie mit dem Datenfluss in reaktbasierten Anwendungen umgegangen wird. Wir werden zunächst die Grundlagen von Flux erläutern und die Motivation hinter seiner Entwicklung verstehen. Anschließend üben wir das Erlernte, indem wir eine einfache virtuelle Wallet-Anwendung erstellen.

Während des gesamten Tutorials gehe ich davon aus, dass Sie React bereits verwendet haben, aber keine Erfahrung mit Flux haben. Sie könnten etwas davon bekommen, wenn Sie bereits die Grundlagen von Flux kennen und ein tieferes Verständnis erlangen möchten.

Wenn Sie mit der React-Szene noch nicht vertraut sind, empfehle ich Ihnen den Einführungskurs von David East, hier bei Envato Tuts +. Es ist ein fantastischer Kurs, der Sie in kürzester Zeit auf den neuesten Stand bringt.

Was ist Fluss??

Fluss ist hauptsächlich ein Anwendungsarchitekturkonzept Von Facebook entwickelt, bezieht sich derselbe Begriff jedoch auch auf eine Bibliothek, die die offizielle Implementierung darstellt.

Facebook brachte Flux als Versuch heraus, die durch das MVC-Muster in ihrer massiven Codebasis verursachten Probleme zu lösen. Sie hatten Probleme mit Problemen, bei denen Aktionen kaskadierende Updates auslösten, die zu unvorhersehbaren Ergebnissen und Code führten, der schwer zu debuggen war. Dies kann Ihnen bekannt vorkommen, wenn Sie bereits MVC-Frameworks verwendet haben, da bei den meisten von ihnen alles eng gekoppelt ist. Fügen Sie dem Mix Beobachter und bidirektionale Datenbindung hinzu, und Sie haben selbst richtige Kopfschmerzen.

Mein Rat ist, jeden Versuch zu vermeiden, Gemeinsamkeiten zwischen Flux und MVC zu finden. Es hilft nicht viel, außer Ihre Verwirrung zu verstärken. Flux-Versuche, Dinge anders zu lösen, und es mit anderen Mustern zu vergleichen, wird nicht helfen.

Projektaufbau

Wenn Sie das Lernprogramm mitverfolgen möchten, stellen Sie zunächst sicher, dass Sie die erforderliche Software installiert haben. Wenn Sie fertig sind, klonen Sie die Kesselplatte Zweig aus dem GitHub-Repository Ich bereitete mich auf diesen Artikel vor.

Hier sind die Softwarevoraussetzungen und die Versionen, die ich zum Zeitpunkt der Erstellung dieses Artikels installiert hatte:

  • Git: 2.11
  • Node.js: 6,9
  • NPM: 3,10
  • Garn: 0,22
  • Ihr Editor Ihrer Wahl

Die Boilerplate dient als Ausgangspunkt für das kommende kleine Projekt, das wir bauen werden, eine kleine virtuelle Wallet-App. Es enthält die Webpack-Konfiguration zum Übertragen der ES6-Syntax in einfaches JavaScript und WDS zum Bereitstellen der Dateien. Es hat auch einige CSS-Komponentenstile, so dass Sie direkt in die Programmierung einsteigen können.

Um alle erforderlichen Abhängigkeiten zu installieren, CD in das Projektverzeichnis und ausführen Garn.

Im nächsten Abschnitt richten Sie die Kernkomponenten der Anwendung ein, bevor Sie Flux integrieren. Ich habe sie nicht in die Heizplatte aufgenommen, da ich glaube, dass dies mehr Verwirrung stiften würde. Wenn Sie nicht an der Erstellung der App interessiert sind, können Sie diese Schritte überspringen und zum nächsten Abschnitt springen.

Komponenten-Setup

Beginnen Sie mit dem Einfügen des folgenden Codes js / index.js, die als Einstiegspunkt der Anwendung dient:

import Reagieren von 'Reagieren'; importiere ReactDOM von 'reag-dom'; App aus './components/App' importieren; ReactDOM.render ((), document.getElementById ('app'));

Für die Hauptsache  erstellen Sie eine neue Datei js / komponenten namens App.js und fügen Sie den folgenden Code hinzu:

import Reagieren von 'Reagieren'; importiere AddNewItem aus './AddNewItem'; ItemsList aus './ItemsList' importieren; Klasse App erweitert React.Component render () return ( 

Flux Wallet

); Standard-App exportieren;

Das  Komponente umschließt zwei andere Komponenten, eine für das Formular, das für das Hinzufügen neuer Elemente verantwortlich ist, und eine weitere für die Liste der Elemente. So erstellen Sie die erstellen Sie eine neue Datei AddNewItem.js Innerhalb js / komponenten und fügen Sie diesen Code hinzu:

import Reagieren von 'Reagieren'; Die Klasse AddNewItem erweitert React.Component // Setzt den Anfangsstatus. Konstruktor (Requisiten) Super (Requisiten); this._getFreshItem = this._getFreshItem.bind (this); this.state = item: this._getFreshItem ();  // Liefert einen neuen Artikel. _getFreshItem () return beschreibung: ", betrag:";  // Aktualisieren Sie den Status. _updateState (event) let field = event.target.name; let value = event.target.value; // Wenn der Betrag geändert wird und es sich nicht um einen Float handelt, wird zurückgegeben. if (Wert && Feld === 'Betrag' &&! value.match (/ ^ [a-z0-9. \ + \ -] + $ / g))  this.state.item [Feld] = Wert; this.setState (item: this.state.item);  // Neues Element hinzufügen. _addNewItem (event) //… render () return ( 

$ 0

$
) export default AddNewItem;

Die Komponente bündelt eine Logik zum Aktualisieren des Status bei der Aktualisierung der Formularfelder sowie einige grundlegende Überprüfungen. Beenden Sie die Einrichtung der Komponenten, indem Sie die letzte Komponente erstellen js / components / ItemsList.js Verwenden Sie diesen Code für die Artikelliste:

import Reagieren von 'Reagieren'; Klasse ItemsList erweitert React.Component Konstruktor (Requisiten) Super (Requisiten); this.state = items: [];  render () let noItemsMessage; // Zeigt stattdessen eine freundliche Nachricht an, wenn keine Elemente vorhanden sind. if (! this.state.items.length) noItemsMessage = (
  • Ihre Geldbörse ist neu!
  • ); Rückkehr (
      noItemsMessage this.state.items.map ((itemDetails) => let amountType = parseFloat (itemDetails.amount)> 0? 'positiv': 'negativ'; return (
    • itemDetails.description itemDetails.amount
    • ); )
    ); Standard-ItemsList exportieren;

    Das ist es! Sie sind mit dem Einrichten der Projektkomponenten fertig. Der große Teil ist, dass sie auch mit kostenlosem Styling kommen.

    Lauf Garnanfang und warten Sie, bis das Bundle aufgebaut ist. Wenn Sie auf Ihren Browser zeigen localhost: 8080, Sie sollten die App ohne Funktionalität sehen.

    Als Nächstes erfahren Sie, was Flux ist und wie Sie es verwenden können, um Funktionen für die virtuelle Geldbörse hinzuzufügen.

    Die Flux-Bausteine

    Auf hoher Ebene gliedert sich Flux in vier Hauptteile: Aktionen, Dispatcher, Stores und Views:

    • Aktionen Beschreiben Sie eine Aktion, die in der Anwendung stattgefunden hat.
    • Der Dispatcher ist eine Einzelregister der Rückrufe. Es fungiert als Zwischenhändler, indem es die Aktionen an alle Läden weiterleitet, die es abonniert haben.
    • Shops Verwalten Sie den Status und die Logik, die zum Aktualisieren für bestimmte Teile der Anwendung erforderlich sind.
    • Ansichten sind einfache alte React-Komponenten.

    In Fluss fließen alle Daten in eine Richtung:

    • Aktionen sind an die übergeben Dispatcher mit Convenience-Klassen aufgerufen Aktionsersteller.
    • Der Dispatcher sendet (verschickt) die Aktionen an alle Shops das abonnierte es.
    • Schließlich, wenn die Shops Wenn es um eine bestimmte Aktion geht (oder mehr), aktualisieren sie ihren Status und signalisieren dem Ansichten so können sie erneut rendern.

    Unten sehen Sie eine visuelle Darstellung dieses Prozesses.

    Aktionen

    Die Daten werden in einer einzigen Richtung durch das Kabel gesendet, wobei einfache JavaScript-Objekte, so genannte Aktionen, verwendet werden. Ihre Aufgabe ist es, ein Ereignis zu beschreiben, das in der Anwendung stattgefunden hat, und die neuen Daten in die Filialen zu transportieren. Jede Aktion muss einen Typ und einen optionalen Payload-Schlüssel haben, der die Daten enthält. Eine Aktion sieht ähnlich aus wie unten:

    actionType: "UPDATE_TITLE", Nutzlast: "Dies ist ein neuer Titel." 

    Der Aktionstyp muss durch eine beschreibende und konsistente Großbuchstabenzeichenfolge dargestellt werden, die der üblichen Konvention der Definition von Konstanten ähnelt. Sie dienen als eindeutige IDs, die von den Shops verwendet werden, um die Aktion zu identifizieren und entsprechend zu reagieren.

    Es ist üblich, alle Aktionstypen in einem Konstantenobjekt zu definieren und dieses Objekt stattdessen in der gesamten Anwendung zu referenzieren, um die Konsistenz zu gewährleisten. Unsere virtuelle Brieftasche unterstützt eine einzige Aktion, die Elemente zur Liste hinzufügt - sowohl Ausgaben als auch finanzielle Gewinne werden als einzelnes Element behandelt. Daher ist unsere Konstantendatei sehr schmal.

    Erstelle ein index.js Datei in der Js / Konstanten Ordner und verwenden Sie den folgenden Code, um Ihren ersten Aktionstyp zu erstellen:

    Exportvorgabe ADD_NEW_ITEM: 'ADD_NEW_ITEM'

    Aktionen werden an den Dispatcher mithilfe von aufgerufenen Hilfsprogrammen für Komfortklassen übergeben Aktionsersteller die die einfache Aufgabe erledigen, die Aktion zu erstellen und an den Dispatcher zu senden. Bevor Sie unseren Aktionsersteller erstellen, sehen Sie zuerst, was der Dispatcher tut, und verstehen Sie seine Rolle in Flux.

    Der Dispatcher

    Der Dispatcher dient zur Koordination der Kommunikation zwischen Aktionserstellern und Filialen. Sie können es verwenden, um den Handler-Callback eines Stores zu registrieren und Aktionen an die Stores zu senden, die abonniert haben.

    Die Dispatcher-API ist einfach und es stehen nur fünf Methoden zur Verfügung:

    • registrieren(): Registriert den Action-Handler-Callback eines Geschäfts.
    • unregister () : Hebt die Rückmeldung eines Geschäfts auf.
    • warten auf(): Wartet, bis die angegebenen Callbacks zuerst ausgeführt werden.
    • Versand(): Sendet eine Aktion aus.
    • isDispatching (): Überprüft, ob der Dispatcher gerade eine Aktion auslöst.

    Die wichtigsten sind registrieren() und Versand() wie sie verwendet werden, um die meisten Kernfunktionen zu handhaben. Mal sehen, wie sie hinter den Kulissen aussehen und arbeiten.

    lassen Sie _callbacks = []; class Dispatcher // Registrieren eines Rückrufs in einem Geschäft. register (callback) let id = 'callback_' + _callbacks.length; _callbacks [id] = callback; ID zurückgeben;  // Eine Aktion auslösen. dispatch (action) für (var id in _callbacks) _callbacks [id] (action); 

    Dies ist natürlich der Grundgedanke. Das registrieren() Methode speichert alle Rückrufe in einem privaten Bereich _Rückrufe Array und Versand() iteriert und ruft jeden gespeicherten Rückruf mit der empfangenen Aktion auf.

    Der Einfachheit halber schreiben wir keinen eigenen Dispatcher. Stattdessen verwenden wir den in der Bibliothek von Facebook bereitgestellten. Ich empfehle Ihnen, das GitHub-Repo von Facebook zu überprüfen und zu sehen, wie es implementiert wird.

    In der js / Dispatcher erstellen Sie eine neue Datei index.js und fügen Sie dieses Code-Snippet hinzu:

    Dispatcher von 'Flux' importieren; voreingestellter neuer Dispatcher () exportieren;

    Es importiert den Dispatcher aus dem Fluss Bibliothek, die zuvor mit Garn installiert wurde, und exportiert dann eine neue Instanz davon.

    Wenn der Dispatcher jetzt bereit ist, können wir zu den Aktionen zurückkehren und den Aktionsersteller unserer App einrichten. In der js / Aktionen Erstellen Sie eine neue Datei mit dem Namen walletActions.js und fügen Sie den folgenden Code hinzu:

    Dispatcher aus '… / Dispatcher' importieren; ActionTypes aus '... / Konstanten' importieren; class WalletActions addNewItem (item) // Anmerkung: Dies ist normalerweise ein guter Ort für API-Aufrufe. Dispatcher.dispatch (actionType: ActionTypes.ADD_NEW_ITEM, Nutzlast: Element);  export default new WalletActions ();

    Das WalletActions Klasse entlarvt ein Neues Element hinzufügen() Methode, die drei grundlegende Aufgaben erledigt:

    • Es erhält eine Artikel als Argument.
    • Mit dem Dispatcher wird eine Aktion mit der NEUES ELEMENT HINZUFÜGEN Aktionstyp, den wir zuvor erstellt haben.
    • Es sendet dann die empfangenen Artikel als Nutzlast zusammen mit dem Aktionstyp.

    Bevor Sie diesen Aktionsersteller einsetzen, sollten Sie sehen, welche Shops in unserer Flux-basierten Anwendung sind und wie sie dazu passen.

    Shops

    Ich weiß, ich sagte, Sie sollten Flux nicht mit anderen Mustern vergleichen, aber Flux-Stores ähneln den Modellen in MVC. Ihre Aufgabe ist es, mit der Logik umzugehen und den Status für eine bestimmte Komponente der obersten Ebene in Ihrer Anwendung zu speichern.

    Alle Flux-Stores müssen eine Action-Handler-Methode definieren, die dann beim Dispatcher registriert wird. Diese Callback-Funktion besteht hauptsächlich aus einer switch-Anweisung für den empfangenen Aktionstyp. Wenn ein bestimmter Aktionstyp erfüllt ist, handelt er entsprechend und aktualisiert den lokalen Status. Schließlich sendet der Store ein Ereignis, um den Ansichten den aktualisierten Status mitzuteilen, damit sie entsprechend aktualisiert werden können.

    Damit Ereignisse gesendet werden können, müssen Geschäfte die Logik eines Ereignissenders erweitern. Es gibt verschiedene Event-Emitter-Bibliotheken, aber die häufigste Lösung ist die Verwendung des Event-Emitters von Node. Für eine einfache App wie eine virtuelle Geldbörse sind nicht mehr als ein Geschäft erforderlich.

    In der js / speichert Erstellen Sie eine neue Datei mit dem Namen walletStore.js und fügen Sie den folgenden Code für den Store unserer App hinzu:

    importiere EventEmitter von 'events'; Dispatcher aus '… / Dispatcher' importieren; ActionTypes aus '... / Konstanten' importieren; const CHANGE = 'CHANGE'; lass _walletState = []; Klasse WalletStore erweitert EventEmitter constructor () super (); // Registriert den Action-Handler beim Dispatcher. Dispatcher.register (this._registerToActions.bind (this));  // Schaltet den Typ der Aktion um, wenn eine Aktion ausgeführt wird. _registerToActions (action) switch (action.actionType) case ActionTypes.ADD_NEW_ITEM: this._addNewItem (action.payload); brechen;  // Fügt der Liste ein neues Element hinzu und gibt ein CHANGED-Ereignis aus. _addNewItem (item) item.id = _walletState.length; _walletState.push (item); this.emit (CHANGE);  // Gibt den Status des aktuellen Speichers zurück. getAllItems () return _walletState;  // Berechne das Gesamtbudget. getTotalBudget () let totalBudget = 0; _walletState.forEach ((item) => totalBudget + = parseFloat (item.amount);); return totalBudget;  // Hängt den Rückruf einer React-Komponente an das CHANGED-Ereignis an. addChangeListener (callback) this.on (CHANGE, callback);  // Entfernt den Listener aus dem CHANGED-Ereignis. removeChangeListener (callback) this.removeListener (CHANGE, callback);  export default new WalletStore ();

    Wir beginnen mit dem Importieren der erforderlichen Abhängigkeiten für das Geschäft, beginnend mit dem Ereignisemitter von Node, dem Dispatcher, gefolgt von den ActionTypes. Sie werden feststellen, dass sich darunter eine Konstante befindet VERÄNDERUNG, ähnlich wie bei den Aktionstypen, über die Sie zuvor informiert wurden. 

    Es ist eigentlich keine, und es sollte nicht verwirrt werden. Diese Konstante wird für den Ereignisauslöser verwendet, wenn sich die Daten des Geschäfts ändern. Wir werden es in dieser Datei behalten, da es kein Wert ist, der in anderen Teilen der Anwendung verwendet wird.

    Bei der Initialisierung der WalletStore Klasse beginnt mit der Registrierung der _registerToAction () Rückruf beim Dispatcher. Hinter den Kulissen wird dieser Rückruf dem Dispatcher hinzugefügt _Rückrufe Array. 

    Die Methode hat eine einzige Schalter Anweisung über den Typ der Aktion, die vom Dispatcher empfangen wird, wenn eine Aktion ausgeführt wird. Wenn es das trifft NEUES ELEMENT HINZUFÜGEN Aktionstyp läuft dann die _Neues Element hinzufügen() Methode und leitet die empfangene Nutzlast weiter.

    Das _Neues Element hinzufügen() Funktion setzt ein Ich würde für das Element, schiebt es zur Liste der vorhandenen Elemente und gibt dann eine aus VERÄNDERUNG Veranstaltung. Als nächstes die getAllItems () und getTotalBudget () Methoden sind grundlegende Methoden, mit denen wir den aktuellen Zustand des Geschäfts und das Gesamtbudget abrufen können.

    Die letzten beiden Methoden, addChangeListener () und removeChangeListener (), wird verwendet, um die React-Komponenten mit der zu verknüpfen WalletStore Sie werden also benachrichtigt, wenn sich die Daten des Geschäfts ändern.

    Controller-Ansichten

    Die Verwendung von React ermöglicht es uns, Teile der Anwendung in verschiedene Komponenten aufzuteilen. Wir können sie verschachteln und interessante Hierarchien erstellen, die auf unserer Seite Arbeitselemente bilden.

    In Flux speichern Komponenten, die sich am oberen Ende der Kette befinden, die meiste Logik, die zum Generieren von Aktionen und zum Empfangen neuer Daten benötigt wird. Daher werden sie Controller-Ansichten genannt. Diese Ansichten sind direkt mit Filialen verknüpft und überwachen die Änderungsereignisse, die ausgelöst werden, wenn die Filialen aktualisiert werden.

    Wenn dies geschieht, rufen Controller-Ansichten das auf setState Methode, die das auslöst machen() Methode zum Ausführen und Aktualisieren der Ansicht und Senden von Daten an untergeordnete Komponenten über Requisiten. Von dort aus reagieren React und das virtuelle DOM auf ihre Weise und aktualisieren das DOM so effizient wie möglich.

    Unsere App ist einfach genug und hält diese Regel nicht ein. Abhängig von der Komplexität können für größere Apps manchmal mehrere Controller-Ansichten mit verschachtelten Unterkomponenten für die Hauptteile der Anwendung erforderlich sein.

    Zusammenpassen

    Wir haben die wichtigsten Teile von Flux fertiggestellt, aber die virtuelle Wallet-App ist noch nicht abgeschlossen. In diesem letzten Abschnitt werden wir den gesamten Fluss von Aktionen bis zu Ansichten überprüfen und den fehlenden Code eingeben, der erforderlich ist, um den unidirektionalen Datenfluss von Flux abzuschließen.

    Aktion absetzen

    Zurück zum Komponente können Sie jetzt die WalletActions Modul und verwenden Sie es, um eine neue Aktion in der zu generieren _Neues Element hinzufügen() Methode.

    import Reagieren von 'Reagieren'; WalletActions aus '… / aktionen / walletActions' importieren; //… _addNewItem (event) event.preventDefault (); this.state.item.description = this.state.item.description || '-'; this.state.item.amount = this.state.item.amount || '0'; WalletActions.addNewItem (this.state.item); this.setState (item: this._getFreshItem ());  //… 

    Wenn nun das Formular gesendet wird, wird eine Aktion ausgelöst und alle Geschäfte - in unserem Fall eine - über die neuen Daten informiert.

    Auf Store-Änderungen warten

    In deiner WalletStore, Wenn derzeit ein Element zur Liste hinzugefügt wird, ändert sich der Status und die VERÄNDERUNG Ereignis wird ausgelöst, aber niemand hört zu. Schließen Sie die Schleife, indem Sie einen Änderungslistener in der Komponente.

    import Reagieren von 'Reagieren'; importiere WalletStore aus '… / stores / walletStore'; Klasse ItemsList erweitert React.Component Konstruktor (Requisiten) Super (Requisiten); this.state = items: WalletStore.getAllItems (); this._onChange = this._onChange.bind (this);  _onChange () this.setState (items: WalletStore.getAllItems ());  componentWillMount () WalletStore.addChangeListener (this._onChange);  componentWillUnmount () WalletStore.removeChangeListener (this._onChange);  render () //… export standard ItemsList;

    Die aktualisierte Komponente schließt den unidirektionalen Datenfluss von Flux. Beachten Sie, dass ich das gesamte übersprungen habe machen() Methode, um Platz zu sparen. Gehen wir Schritt für Schritt durch die Neuerungen:

    • Das WalletStore Modul ist oben enthalten.
    • Der Anfangszustand wird aktualisiert, um stattdessen den Zustand des Geschäfts zu verwenden.
    • Ein neuer _bei Änderung() Diese Methode wird verwendet, um den Status mit den neuen Daten aus dem Speicher zu aktualisieren.
    • Mithilfe der Lebenszyklus-Hooks von React _bei Änderung() Rückruf wird als Änderungslistener-Rückruf des Geschäfts hinzugefügt und entfernt.

    Fazit

    Glückwunsch! Sie haben die Erstellung einer funktionierenden virtuellen Wallet-App von Flux abgeschlossen. Sie haben gelernt, wie alle Flux-Komponenten miteinander interagieren und wie Sie mit React-Apps Struktur hinzufügen können.

    Wenn Sie sich in Ihren Flux-Fähigkeiten sicher fühlen, sollten Sie auch andere Flux-Implementierungen wie Alt, Delorean, Flummox oder Fluxxor ausprobieren und herausfinden, welche sich für Sie am besten eignet.

    Lassen Sie mich in den Kommentaren unten Ihre Meinung wissen, ich würde gerne wissen, was Sie über Flux denken, oder Sie unterstützen, wenn Sie Schwierigkeiten haben, dem Tutorial zu folgen. Wenn Sie möchten, können Sie mich auch über Twitter @hiskio erreichen.