Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Web Development

Einführung in das React Framework

by
Difficulty:IntermediateLength:LongLanguages:

German (Deutsch) translation by Władysław Łucyszyn (you can also view the original English article)

In der heutigen Welt der Javascript Application Frameworks ist Design-Philosophie der entscheidende Differenzierungsfaktor. Wenn Sie die gängigen JS-Frameworks wie EmberJS, AngularJS, Backbone, Knockout usw. vergleichen, werden Sie sicher Unterschiede in ihren Abstraktionen, Denkmodellen und natürlich der Terminologie finden. Dies ist eine direkte Konsequenz der zugrundeliegenden Designphilosophie. Aber im Prinzip tun sie alle eins, nämlich das DOM so zu abstrahieren, dass Sie nicht direkt mit HTML Elements arbeiten.

Ich persönlich denke, dass ein Framework interessant wird, wenn es eine Reihe von Abstraktionen bietet, die eine andere Denkweise ermöglichen. In diesem Aspekt, react Sie, das neue JS-Framework von den Leuten bei Facebook, wird Sie zwingen, (bis zu einem gewissen Grad) zu überdenken, wie Sie die Benutzeroberfläche und Interaktionen Ihrer Anwendung zerlegen. Nach der Version 0.4.1 (zum jetzigen Zeitpunkt) bietet React ein überraschend einfaches, aber effektives Modell zum Erstellen von JS-Apps, das einen köstlichen Cocktail einer anderen Art mischt.

In diesem Artikel werden wir die Bausteine von React erforschen und einen Denkstil annehmen, der auf den ersten Blick kontraintuitiv erscheint. Aber, wie die React-Dokumentation sagt: "Gib es fünf Minuten", und dann wirst du sehen, wie dieser Ansatz natürlicher wird.

Motivationen

Die Geschichte von React begann innerhalb der Grenzen von Facebook, wo es für eine Weile gebraut wurde. Nachdem sie einen stabilen Zustand erreicht hatten, beschlossen die Entwickler, sie vor ein paar Monaten zu öffnen. Interessanterweise wird die Instagram-Website auch vom React Framework unterstützt.

React nähert sich dem DOM-Abstraktionsproblem mit einer etwas anderen Einstellung. Um zu verstehen, wie das anders ist, wollen wir die Techniken, die von den oben erwähnten Frameworks übernommen wurden, schnell beschönigen.

Eine übergeordnete Übersicht über JS Application Frameworks

Das MVC-Entwurfsmuster (Model-View-Controller) ist grundlegend für die UI-Entwicklung, nicht nur in Web-Apps, sondern auch in Front-End-Anwendungen auf jeder Plattform. Im Fall von Web-Apps ist das DOM die physische Darstellung einer Ansicht. Das DOM selbst wird aus einer textuellen HTML-Vorlage generiert, die aus einer anderen Datei, einem Skriptblock oder einer vorkompilierten Template-Funktion stammt. Die View ist eine Entität, die die Textvorlage als DOM-Fragment zum Leben erweckt. Es richtet auch Event-Handler ein und kümmert sich darum, den DOM-Baum als Teil seines Lebenszyklus zu manipulieren.

Damit die View nützlich ist, muss sie einige Daten anzeigen und möglicherweise Benutzerinteraktionen ermöglichen. Bei den Daten handelt es sich um das Model, das aus einer Datenquelle stammt (Datenbank, Web-Service, lokaler Speicher usw.). Frameworks bieten eine Möglichkeit zum "Binden" der Daten an die Ansicht, sodass Änderungen in Daten automatisch mit Änderungen in der Ansicht widergespiegelt werden. Dieser automatische Vorgang wird Datenbindung genannt und es gibt APIs / Techniken, um dies so nahtlos wie möglich zu machen.

Die MVC-Triade wird durch den Controller vervollständigt, der die View und das Model aktiviert und den Datenfluss (Model) in die View und Benutzerereignisse außerhalb der View orchestriert, was möglicherweise zu Änderungen im Model führt.

mvc-flow

Frameworks, die den Datenfluss zwischen Ansicht und Modell automatisch verarbeiten, behalten eine interne Ereignisschleife bei. Diese Ereignisschleife wird benötigt, um bestimmte Benutzerereignisse, Datenänderungsereignisse, externe Auslöser usw. zu überwachen und dann festzustellen, ob sich eine Änderung gegenüber dem vorherigen Durchlauf der Schleife ergibt. Wenn an beiden Enden Änderungen vorgenommen werden (Ansicht oder Modell), stellt das Framework sicher, dass beide synchronisiert werden.

Was unterscheidet Reaktionen?

Mit React wird der View-Teil der MVC-Triade hervorgehoben und in eine Entität namens Component gerollt. Die Komponente verwaltet eine unveränderbare Eigenschaftstasche mit dem Namen props und einen state, der den benutzergesteuerten Zustand der Benutzeroberfläche darstellt. Der View-Generations-Teil der Compnent ist ziemlich interessant und möglicherweise der Grund dafür, dass React sich von anderen Frameworks abhebt. Anstatt ein physisches DOM direkt aus einer Vorlagendatei / einem Skript / einer Funktion zu konstruieren, generiert die Component ein intermediäres DOM, das eine Stand-in-Funktion für das echte HTML-DOM darstellt. Ein zusätzlicher Schritt wird dann unternommen, um dieses Zwischen-DOM in das echte HTML-DOM zu übersetzen.

Als Teil der intermediären DOM-Generierung fügt die Component auch Ereignishandler hinzu und bindet die Daten in props und state.

Wenn die Idee eines Intermediate-DOM ein wenig fremd klingt, seien Sie nicht zu alarmiert. Sie haben diese Strategie bereits bei Sprachlaufzeiten (auch bekannt als virtuelle Maschinen) für interpretierte Sprachen gesehen. Unsere eigene JavaScript-Laufzeit generiert zuerst eine Zwischenrepräsentation, bevor der native Code ausgegeben wird. Dies gilt auch für andere VM-basierte Sprachen wie Java, C #, Ruby, Python usw.

Reagieren Sie geschickt diese Strategie, um ein intermediäres DOM zu erstellen, bevor Sie das endgültige HTML-DOM generieren. Das intermediate-DOM ist nur ein JavaScript-Objektdiagramm und wird nicht direkt gerendert. Es gibt einen Übersetzungsschritt, der das echte DOM erstellt. Dies ist die zugrunde liegende Technik, mit der React schnelle DOM-Manipulationen durchführt.

Reagiert in Tiefe

Um ein besseres Bild davon zu bekommen, wie React alles funktioniert, tauchen wir ein wenig tiefer auf; beginnend mit der Component. Die Komponente ist der primäre Baustein in React. Sie können die Benutzeroberfläche Ihrer Anwendung zusammenstellen, indem Sie eine Baumstruktur aus Komponenten zusammenstellen. Jede Komponente stellt eine Implementierung für die render() -Methode bereit, in der sie das intermediate-DOM erstellt. Wenn Sie React.renderComponent() für die root-Komponente aufrufen, wird der Komponentenbaum rekursiv durchlaufen und das intermediate-DOM aufgebaut. Das Intermediate-DOM wird dann in das echte HTML-DOM konvertiert.

component-dom-tree

Da die Intermediate-DOM-Erstellung ein integraler Bestandteil der Komponente ist, stellt React eine praktische XML-basierte Erweiterung von JavaScript namens JSX bereit, um den Komponentenbaum als eine Menge von XML-Knoten zu erstellen. Dies macht es einfacher, das DOM zu visualisieren und zu begründen. JSX vereinfacht auch die Zuordnung von Event-Handlern und Eigenschaften als XML-Attribute. Da JSX eine Erweiterungssprache ist, gibt es ein Tool (Befehlszeile und In-Browser), um das endgültige JavaScript zu generieren. Ein JSX XML-Knoten wird direkt einer Komponente zugeordnet. Es lohnt sich, darauf hinzuweisen, dass React unabhängig von JSX arbeitet und die JSX-Sprache nur die Erstellung des DOM-Intermediates erleichtert.

Werkzeuge

Das Kernreactor-Framework kann von seiner Website heruntergeladen werden. Darüber hinaus können Sie für die JSX → JS-Umwandlung entweder den JSXTransformer im Browser verwenden oder das Befehlszeilentool react-tools (installiert über NPM) verwenden. Sie benötigen eine Installation von Node.js, um es herunterzuladen. Mit dem Befehlszeilentool können Sie JSX-Dateien vorkompilieren und die Übersetzung im Browser vermeiden. Dies wird definitiv empfohlen, wenn Ihre JSX-Dateien groß oder zahlreich sind.

Eine einfache Komponente

Okay, wir haben bis jetzt eine Menge Theorie gesehen und ich bin sicher, dass es dich reizt, einen echten Code zu sehen. Lassen Sie uns in unser erstes Beispiel eintauchen:

Obwohl es einfach ist, deckt der obige Code einen guten Teil der React-Oberfläche ab:

  • Wir erstellen die einfache Komponente, indem wir React.createClass verwenden und ein Objekt übergeben, das einige Kernfunktionen implementiert. Die wichtigste ist die render(), die das intermediate-DOM generiert.
  • Hier verwenden wir JSX, um das DOM zu definieren und den mousedown-Event-Handler anzuhängen. Die Syntax {} eignet sich zum Einbinden von JavaScript-Ausdrücken für Attribute (onMouseDown = {this.handleClick}) und untergeordnete Knoten (<span class="count">{this.state.count}</span>). Ereignishandler, die mit der Syntax {} verknüpft sind, werden automatisch an die Instanz der Komponente gebunden. Somit bezieht this dies innerhalb der Ereignisbehandlungsfunktion auf die Komponenteninstanz. Der Kommentar in der ersten Zeile / ** @jsx React.DOM * / ist ein Hinweis für den JSX-Transformer, die Übersetzung in JS durchzuführen. Ohne diese Kommentarzeile findet keine Übersetzung statt.

Wir können das Befehlszeilentool (jsx) im Überwachungsmodus ausführen und Änderungen von JSX → JS automatisch kompilieren. Die Quelldateien befinden sich im Ordner /src, und die Ausgabe wird in /build generiert.

Hier ist die generierte JS-Datei:

Beachten Sie, wie die Tags <div/> und <span/> den Instanzen von React.DOM.div und React.DOM.span zugeordnet werden.

  • Kommen wir nun zu unserem Codebeispiel zurück. Innerhalb von handleMouseDown verwenden wir this.props, um die Message-Eigenschaft zu lesen, die übergeben wurde. Wir haben die message in der letzten Zeile des Snippets im Aufruf von React.renderComponent() gesetzt. wo wir die <Simple/> Komponente erstellen. Der Zweck von this.props besteht darin, die Daten zu speichern, die an die Komponente übergeben wurden. Es wird als unveränderlich betrachtet und nur eine übergeordnete Komponente darf Änderungen vornehmen und sie im Komponentenbaum weiterleiten.
  • Innerhalb von handleMouseDown setzen wir auch einen Benutzerstatus mit this.setState(), um zu verfolgen, wie oft die Nachricht angezeigt wurde. Sie werden feststellen, dass wir this.state in der render() -Methode verwenden. Immer wenn Sie setState() aufrufen, löst React auch die Methode render() aus, um das DOM synchron zu halten. Neben React.renderComponent(), setState() ist eine weitere Möglichkeit, eine visuelle Aktualisierung zu erzwingen.

Synthetische Ereignisse

Die Ereignisse, die im intermediate-DOM angezeigt werden, z. B. onMouseDown, fungieren auch als eine indirekte Ebene, bevor sie im Real-DOM festgelegt werden. Diese Ereignisse werden daher als synthetische Ereignisse bezeichnet. React übernimmt Event-Delegation, eine bekannte Technik, und fügt Ereignisse nur auf der Root-Ebene des Real-DOM an. Somit gibt es nur einen echten Event-Handler auf dem Real-DOM. Zusätzlich bieten diese synthetischen Ereignisse eine gewisse Konsistenz, indem Browser- und Elementunterschiede ausgeblendet werden.

Die Kombination aus Intermediate-DOM und synthetischen Ereignissen bietet Ihnen eine einheitliche und konsistente Möglichkeit, UIs über verschiedene Browser und sogar Geräte hinweg zu definieren.

Komponentenlebenszyklus

Komponenten im React-Framework haben einen bestimmten Lebenszyklus und verkörpern eine Zustandsmaschine mit drei verschiedenen Zuständen.

component-lifecycle

Die Komponente wird lebendig, nachdem sie montiert wurde. Das Mounten führt zu einem Render-Durchlauf, der den Komponentenbaum (Intermediate-DOM) generiert. Dieser Baum wird konvertiert und in einen Container-Knoten des realen DOMs platziert. Dies ist ein direktes Ergebnis des Aufrufs von React.renderComponent().

Nach dem Mounten bleibt die Komponente im Status Update. Eine Komponente wird aktualisiert, wenn Sie den Status mithilfe von setState() ändern oder Requisiten mithilfe von setProps() ändern. Dies führt wiederum zum Aufruf von render(), wodurch das DOM mit den Daten synchronisiert wird (props + state). Zwischen nachfolgenden Aktualisierungen berechnet React das Delta zwischen dem vorherigen Komponentenbaum und dem neu erzeugten Baum. Dies ist ein hoch optimierter Schritt (und ein Flaggschiff-Feature), der die Manipulation am echten DOM minimiert.

Der Endstatus ist Nicht montiert. Dies geschieht, wenn Sie React.unmountAndReleaseReactRootNode() oder automatisch aufrufen, wenn eine Komponente ein Kind war, das nicht mehr in einem Aufruf von render() generiert wurde. Meistens müssen Sie sich nicht damit befassen und lassen Sie React einfach das Richtige tun.

Jetzt wäre es eine große Nachsicht gewesen, wenn React Ihnen nicht gesagt hätte, wann es zwischen den Zuständen Mounted-Update-Unmounted und Mounted-Update-Unmounted verschoben wurde. Glücklicherweise ist das nicht der Fall und es gibt Hooks, die Sie außer Kraft setzen können, um über Änderungen am Lebenszyklus benachrichtigt zu werden. Die Namen sprechen für sich:

  • getInitialState(): Bereite den Anfangszustand der Komponente vor
  • componentWillMount()
  • componentDidMount()
  • componentWillReceiveProps()
  • shouldComponentUpdate(): nützlich, wenn Sie steuern möchten, wann ein Rendern übersprungen werden soll.
  • componentWillUpdate()
  • render()
  • componentDidUpdate()
  • componentWillUnmount()

Die componentWill* -Methoden werden vor der Statusänderung aufgerufen und die componentDid* -Methoden werden danach aufgerufen.

Einige der Methodennamen werden von den Cocoa-Frameworks in Mac und iOS übernommen

Verschiedene Funktionen

Innerhalb eines Komponentenbaums sollten Daten immer nach unten fließen. Eine übergeordnete Komponente sollte die props einer untergeordneten Komponente so einstellen, dass Daten vom übergeordneten an das untergeordnete Element übergeben werden. Dies wird als Owner-Owned-Paar bezeichnet. Auf der anderen Seite werden Benutzerereignisse (Maus, Tastatur, Berührungen) immer vom Kind bis zur Wurzelkomponente aufsteigen, außer wenn dazwischen gehandelt wird.

data-event-flow

Wenn Sie das intermediate-DOM in render() erstellen, können Sie einer untergeordneten Komponente auch eine ref-Eigenschaft zuweisen. Sie können dann mithilfe der Eigenschaft refs auf das übergeordnete Element verweisen. Dies ist im folgenden Ausschnitt dargestellt.

Als Teil der Komponentenmetadaten können Sie den Anfangszustand (getInitialState()) festlegen, den wir zuvor in den Lebenszyklusmethoden gesehen haben. Sie können auch die Standardwerte der Requisiten mit getDefaultProps() festlegen und einige Validierungsregeln für diese Requisiten mit propTypes festlegen. Die Dokumente geben einen guten Überblick über die verschiedenen Arten von Validierungen (Typprüfungen, erforderlich usw.), die Sie durchführen können.

React unterstützt auch das Konzept eines Mixins, um wiederverwendbare Verhaltensweisen zu extrahieren, die in verschiedene Komponenten injiziert werden können. Sie können die Mixins mit der Mixins-Eigenschaft einer Komponente übergeben.

Lasst uns jetzt real werden und eine umfassendere Komponente erstellen, die diese Funktionen nutzt.

Ein Shape Editor, der mit React erstellt wurde

In diesem Beispiel erstellen wir einen Editor, der eine einfache DSL (domänenspezifische Sprache) zum Erstellen von Formen akzeptiert. Während Sie tippen, sehen Sie die entsprechende Ausgabe auf der Seite und erhalten Live-Feedback.

Mit der DSL können Sie drei Arten von Formen erstellen: Ellipse, Rechteck und Text. Jede Form wird in einer separaten Zeile zusammen mit einer Reihe von Styling-Eigenschaften angegeben. Die Syntax ist einfach und leiht sich etwas von CSS. Um eine Zeile zu analysieren, verwenden wir eine Regex, die wie folgt aussieht:

Als Beispiel beschreibt der folgende Satz von Linien zwei Rechtecke und eine Textbeschriftung...

...erzeugt die Ausgabe wie folgt:

react-shapes

Einrichten

Okay, lass uns weitermachen und diesen Editor erstellen. Wir beginnen mit der HTML-Datei (index.html), Hier fügen wir das Top-Level-Markup ein und enthalten die Bibliotheken und Anwendungsskripte. Ich zeige nur die relevanten Teile hier:

Im obigen Snippet enthält der Container-div unser React generated DOM. Unsere Anwendungsskripte sind im Verzeichnis /build enthalten. Wir verwenden JSX innerhalb unserer Komponenten und der Command Line Watcher (jsx), setzt die konvertierten JS-Dateien in /build. Beachten Sie, dass dieser Watcher-Befehl Teil des NPM-Moduls react-tools ist.

Der Editor ist in eine Reihe von Komponenten unterteilt, die nachfolgend aufgeführt sind:

  • ShapeEditor: Die Stammkomponente in der Komponentenstruktur
  • ShapeCanvas: verantwortlich für die Generierung der Shape-Komponenten (Ellipse, Rectangle, Text). Es ist im ShapeEditor enthalten.
  • ShapeParser: Verantwortlich für das Parsen von Text und das Extrahieren der Liste der Formdefinitionen. Es analysiert Zeile für Zeile mit der Regex, die wir zuvor gesehen haben. Ungültige Zeilen werden ignoriert. Dies ist nicht wirklich eine Komponente, sondern ein Helfer-JS-Objekt, das vom ShapeEditor verwendet wird.
  • Ellipse, Rechteck, Text: die Form Komponenten. Diese werden zu Kindern der ShapeCanvas.
  • ShapePropertyMixin: stellt Hilfsfunktionen zum Extrahieren von Stilen bereit, die in den Formdefinitionen gefunden werden. Dies wird in die drei Shape-Komponenten unter Verwendung der Mixins-Eigenschaft gemischt.
  • App: der Einstiegspunkt für den Editor. Er generiert die Root-Komponente (ShapeEditor) und ermöglicht die Auswahl eines Shapes aus dem Drop-down-Menü.

Die Beziehung dieser Entitäten wird im annotierten Komponentenbaum angezeigt:

component-tree

Die ShapeEditor-Komponente

Sehen wir uns die Implementierung einiger dieser Komponenten an, beginnend mit dem ShapeEditor.

Wie der Name schon sagt, bietet der ShapeEditor die Möglichkeit zum Bearbeiten, indem er <textarea/> und das Live-Feedback zu <ShapeCanvas/>. Er überwacht das onChange-Ereignis (Ereignisse in React werden immer mit camel case benannt) für <textarea/> und legt bei jeder Änderung die text -Eigenschaft des state der Komponente fest. Wie bereits erwähnt, wird beim Rendern des Zustands mit setState() das Rendern automatisch aufgerufen. In diesem Fall wird die render() des ShapeEditors aufgerufen, wo wir den Text aus dem Zustand analysieren und die Shapes neu erstellen. Beachten Sie, dass wir mit einem Anfangszustand von leerem Text beginnen, der im getInitialState() - Hook gesetzt ist.

Um den Text in eine Reihe von Formen zu zerlegen, verwenden wir eine Instanz von ShapeParser. Ich habe die Details des Parsers weggelassen, um die Diskussion auf React zu konzentrieren. Die Parserinstanz wird im componentWillMount() - Hook erstellt. Dies wird kurz vor dem Mounten der Komponente aufgerufen und ist ein guter Ort, um vor dem ersten Rendern Initialisierungen durchzuführen.

Im Allgemeinen wird empfohlen, dass Sie Ihre gesamte komplexe Verarbeitung über die render() - Methode durchführen. Event-Handler legen nur den Status fest, während render() der Hub für all Ihre Kernlogik ist.

Der ShapeEditor verwendet diese Idee, um das Parsen innerhalb von render() durchzuführen und leitet die erkannten Formen weiter, indem er die shapes - Eigenschaft von ShapeCanvas festlegt. Auf diese Weise fließen Daten vom Eigentümer (ShapeEditor) zum Eigentümer (ShapeCanvas) in den Komponentenbaum.

Eine letzte Sache, die hier zu beachten ist, ist, dass wir den ersten Zeilenkommentar haben, um die JSX → JS-Übersetzung anzuzeigen.

ShapeCanvas zum Generieren der Formen

Als nächstes gehen wir zu den Komponenten ShapeCanvas und Ellipse, Rectangle und Text über.

p> Die ShapeCanvas ist ziemlich einfach mit ihrer Kernverantwortung, die entsprechenden <Ellipse/> Komponenten <Rectangle/>, und <Text/> aus den übergebenen Formdefinitionen (this.props.shapes) zu generieren. Für jede Form übergeben wir die analysierten Eigenschaften mit dem Attribut expression: properties={shape.properties}.

Eine Sache, die anders ist, ist, dass unser Komponentenbaum nicht statisch ist, wie wir es in ShapeEditor haben. Stattdessen wird es dynamisch generiert, indem die übergebenen Shapes durchlaufen werden. Wir zeigen auch die Meldung "No Shapes Found", wenn nichts zu zeigen ist.

Die Formen: Ellipse, Rechteck, Text

Alle Formen haben eine ähnliche Struktur und unterscheiden sich nur im Styling. Sie verwenden auch den ShapePropertyMixin, um mit der Stilgenerierung umzugehen.

Hier ist Ellipse:

Die Implementierung für extractStyle() wird von ShapePropertyMixin bereitgestellt.

Die Rectangle-Komponente folgt natürlich ohne den Border-Radius-Stil. Die Textkomponente hat eine zusätzliche Eigenschaft namens value, die den inneren Text für festlegt <div/>.

Hier ist Text, um das zu verdeutlichen:

Alles mit App.js verbinden

Mit app.js bringen wir alles zusammen. Hier rendern wir die Root-Komponente, den ShapeEditor, und bieten auch Unterstützung für den Wechsel zwischen einigen Beispielformen. Wenn Sie ein anderes Sample aus dem Drop-down-Menü auswählen, laden wir einen vordefinierten Text in den ShapeEditor und führen zur Aktualisierung von ShapeCanvas. Dies geschieht in der readShapes() -Methode.

Um die kreative Seite auszuüben, hier ein Roboter, der mit dem Form-Editor erstellt wurde:

robot

Und das ist Reaktion für dich!

Puh! Dies war ein ziemlich langer Artikel und nachdem Sie diesen Punkt erreicht haben, sollten Sie ein Erfolgserlebnis haben!

Wir haben hier eine Menge Konzepte untersucht: die integrale Rolle von Komponenten im Framework, die Verwendung von JSX zum einfachen Beschreiben eines Komponentenbaums (aka Intermediate-DOM), verschiedene Hooks zum Einklinken in das Komponentenlebenszyklus, die Verwendung von State und Props zum Fahren Renderprozess, Verwendung von Mixins, um wiederverwendbares Verhalten herauszufiltern und schließlich all dies zusammen mit dem Shape Editor-Beispiel zu kombinieren.

Ich hoffe, dieser Artikel gibt Ihnen genug Schubkraft, um ein paar React-Apps für sich selbst zu erstellen. Um Ihre Erkundung fortzusetzen, hier sind einige praktische Links:

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.