Web-Entwicklung mit React - Cortex Brainware · 2016. 3. 30. · Web-Entwicklung mit React Eine...

12
Web-Entwicklung mit React Eine Einführung in die Nutzung von React Zusammenfassung Die von Facebook veröffentlichte Bibliothek React soll die Entwicklung von großen (Web-) Applikationen vereinfachen, die Daten darstellen, die sich mit der Zeit ändern. Im Vordergrund steht eine möglichst einfache und fehlerarme Implementierung der Reaktion auf Datenänderungen. Dabei verfolgt React einen stark Komponenten-orientierten Ansatz, so dass fertige Lösungen anderer Entwickler sehr leicht in die eigene Applikation eingebunden werden können. Dazu unterstützt React ein striktes Programmiermodell, das die Manipulation der Darstellung einfach und robust macht. Was ist React? React ist eine Bibliothek für die komponentenbasierte Erstellung von dynamischen Web-Applikationen. React wurde von Facebook für den Eigengebrauch entwickelt und der Allgemeinheit zur Verfügung gestellt. React ist Open-Source und unterliegt der BSD-Lizenz. Facebook schreibt dazu: We built React to solve one problem: building large applications with data that changes over time. Das Ziel von React ist es, die Modifikation des DOM-Baums einer Web-Seite nach der Änderung von Daten einerseits für den Entwickler so einfach wie möglich zu machen und dabei andererseits effizient zu bleiben, damit auch große Anwendungen möglich sind. Das Ergebnis ist eine mächtige Bibliothek, die das Erstellen von komplexen Web-Anwendungen sehr gut unterstützt. Der komponentenbasierte Ansatz macht es einfach, Funktionalität in Form von React-Komponenten wiederverwendbar zu implementieren. Dementsprechend gibt es im Netz zu vielen Aufgaben bereits fertige Komponenten, die ohne weiteres in eigenen Projekten eingesetzt werden können. Nach der Fertigstellung der ersten Versionen erkannten die Entwickler von React, dass das Kernkonzept der Bibliothek sich nicht nur für HTML-basierte Anwendungen eignet, sondern von der UI-Technologie unabhängig ist. Mit Version 0.14 wurde die ursprünglich monolithische Bibliothek daher geteilt. Der HTML- bzw. DOM-spezifische Teil (react-dom.js) wurde vom eigentlichen Kern (react.js) getrennt. Dieser Kern ist nun auch Grundlage anderer React-Module. Facebook selbst entwickelt mit react-native eine Unterstützung für die React-basierte Programmierung von iOS und Android unter Verwendung der nativen Controls der jeweiligen Plattform. Daneben gibt es zum Beispiel react-canvas, das auf das Rendern in einen HTML-Canvas spezialisiert ist. Für die Nutzung in einer Web-Applikation müssen seit dieser Aufteilung beide genannten Javascript-Dateien in die Seiten eingebunden werden. Weiteres Wissen um die interne Struktur ist nicht erforderlich. Die vollständige Dokumentation zu React sowie Download-Links finden Sie unter https://facebook.github.io/react . Dieser Artikel geht nicht auf alle Details ein, sondern vermittelt einige Grundlagen. Wie die Überschrift bereits andeutet, wird konzentriert sich dieser Artikel auf die Nutzung von React für die Erstellung von Web-Anwendungen.

Transcript of Web-Entwicklung mit React - Cortex Brainware · 2016. 3. 30. · Web-Entwicklung mit React Eine...

Page 1: Web-Entwicklung mit React - Cortex Brainware · 2016. 3. 30. · Web-Entwicklung mit React Eine Einführung in die Nutzung von React Zusammenfassung Die von Facebook veröffentlichte

Web-Entwicklung mit React

Eine Einführung in die Nutzung von React

Zusammenfassung

Die von Facebook veröffentlichte Bibliothek React soll die Entwicklung von großen (Web-) Applikationen

vereinfachen, die Daten darstellen, die sich mit der Zeit ändern. Im Vordergrund steht eine möglichst

einfache und fehlerarme Implementierung der Reaktion auf Datenänderungen. Dabei verfolgt React

einen stark Komponenten-orientierten Ansatz, so dass fertige Lösungen anderer Entwickler sehr leicht in

die eigene Applikation eingebunden werden können. Dazu unterstützt React ein striktes

Programmiermodell, das die Manipulation der Darstellung einfach und robust macht.

Was ist React?

React ist eine Bibliothek für die komponentenbasierte Erstellung von dynamischen Web-Applikationen.

React wurde von Facebook für den Eigengebrauch entwickelt und der Allgemeinheit zur Verfügung

gestellt. React ist Open-Source und unterliegt der BSD-Lizenz.

Facebook schreibt dazu:

We built React to solve one problem: building large applications with data that changes over time.

Das Ziel von React ist es, die Modifikation des DOM-Baums einer Web-Seite nach der Änderung von

Daten einerseits für den Entwickler so einfach wie möglich zu machen und dabei andererseits effizient

zu bleiben, damit auch große Anwendungen möglich sind. Das Ergebnis ist eine mächtige Bibliothek, die

das Erstellen von komplexen Web-Anwendungen sehr gut unterstützt.

Der komponentenbasierte Ansatz macht es einfach, Funktionalität in Form von React-Komponenten

wiederverwendbar zu implementieren. Dementsprechend gibt es im Netz zu vielen Aufgaben bereits

fertige Komponenten, die ohne weiteres in eigenen Projekten eingesetzt werden können.

Nach der Fertigstellung der ersten Versionen erkannten die Entwickler von React, dass das Kernkonzept

der Bibliothek sich nicht nur für HTML-basierte Anwendungen eignet, sondern von der UI-Technologie

unabhängig ist. Mit Version 0.14 wurde die ursprünglich monolithische Bibliothek daher geteilt. Der

HTML- bzw. DOM-spezifische Teil (react-dom.js) wurde vom eigentlichen Kern (react.js) getrennt. Dieser

Kern ist nun auch Grundlage anderer React-Module. Facebook selbst entwickelt mit react-native eine

Unterstützung für die React-basierte Programmierung von iOS und Android unter Verwendung der

nativen Controls der jeweiligen Plattform. Daneben gibt es zum Beispiel react-canvas, das auf das

Rendern in einen HTML-Canvas spezialisiert ist. Für die Nutzung in einer Web-Applikation müssen seit

dieser Aufteilung beide genannten Javascript-Dateien in die Seiten eingebunden werden. Weiteres

Wissen um die interne Struktur ist nicht erforderlich.

Die vollständige Dokumentation zu React sowie Download-Links finden Sie unter

https://facebook.github.io/react. Dieser Artikel geht nicht auf alle Details ein, sondern vermittelt einige

Grundlagen. Wie die Überschrift bereits andeutet, wird konzentriert sich dieser Artikel auf die Nutzung

von React für die Erstellung von Web-Anwendungen.

Page 2: Web-Entwicklung mit React - Cortex Brainware · 2016. 3. 30. · Web-Entwicklung mit React Eine Einführung in die Nutzung von React Zusammenfassung Die von Facebook veröffentlichte

Wie funktioniert React?

Ein "React-Programm" besteht aus einer Reihe von ineinander geschachtelten Komponenten, die in

HTML-Elemente übersetzt werden, so dass der Browser sie anzeigen kann. Diese Übersetzung von

Komponenten in HTML-Elemente erfolgt jedoch nicht direkt. React verwendet für diese Aufgabe ein

sogenanntes „virtuelles DOM”. Das ist eine leichtgewichtigere Darstellung der HTML-Elemente in Form

von JavaScript-Objekten. Das so erzeugte virtuelle DOM der HTML-Seite bzw. eines Teils davon wird

anschließend in echte HTML-Elemente umgewandelt. Diese Übersetzung von Komponenten in ein

virtuelles DOM bzw. in echtes HTML wird Rendering genannt.

Als Entwickler sieht man nicht viel von dieser Komplexität. Eine React-Komponente ist zunächst einmal

nur eine JavaScript-Klasse mit einer Methode namens render(), die HTML-Elemente ausgibt. Am

einfachsten programmiert sich eine solche Komponente nicht in purem JavaScript, sondern in einer

Erweiterung der Sprache namens JSX. Deren Syntax erlaubt im Prinzip das Einbetten von DOM-Stücken

in eine JavaScript-Datei. Eine ganz einfache Komponente sieht als JSX-Datei so aus:

var HelloWorld = React.createClass({

render: function () {

return (

<div>Hello World!</div>

);

}

});

Dieses Stückchen Code erzeugt eine Komponente namens "HelloWorld", die entweder alleine oder als

Teil von weiteren Komponenten verwendet werden kann. Wie man an dem return-Statement sieht,

erlaubt JSX anders als JavaScript das direkte Einbetten von HTML-Elementen in den Code.

Genau genommen handelt es sich bei dem div-Element im Code nicht um ein HTML-div-Element.

Vielmehr wird hier eine eingebaute Komponente von React verwendet, die 1:1 in ein div-Element

übersetzt wird. React bietet für alle HTML-Elemente (wie div, span, img) solche vordefinierten

Komponenten. Selbst dieses einfache Beispiel nutzt also bereits die Komposition von Komponenten.

Auch selbstdefinierte Komponenten wie HelloWorld können in JSX-Code in der von HTML gewöhnten

Schreibweise genutzt werden. Das sieht etwa so aus:

var HelloWorldUser = React.createClass({

render: function () {

return <HelloWorld/>;

}

});

An diesem Beispiel sieht man auch, dass die runden Klammern im Return-Statement nicht zwingend

erforderlich sind. Sie werden nur benötigt, wenn der Ausdruck mehrere Zeilen umfasst.

Ein Markup-Teil wie <HelloWorld/> ist dabei nichts anderes al ein JavaScript-Ausdruck. Dieser Ausdruck

kann mittels return von einer Funktion zurückgegeben, aber auch einer Variablen zugewiesen oder in

ein Array eingefügt werden.

Hinter den Kulissen werden JSX-Dateien in ganz konventionelles JavaScript übersetzt. Die beiden obigen

Snippets sehen nach der Übersetzung dann etwa so aus:

Page 3: Web-Entwicklung mit React - Cortex Brainware · 2016. 3. 30. · Web-Entwicklung mit React Eine Einführung in die Nutzung von React Zusammenfassung Die von Facebook veröffentlichte

var HelloWorld = React.createClass({

displayName: "HelloWorld",

render: function render() {

return React.createElement(

"div",

null,

"Hello World!"

);

}

});

var HelloWorldUser = React.createClass({

displayName: "HelloWorldUser",

render: function render() {

return React.createElement(HelloWorld, null);

}

});

Diesen Code führt der Browser dann mittels seiner eingebauten JavaScript-Engine aus. Als Entwickler

kann man auch diese reine JavaScript-Form natürlich auch für die Entwicklung nutzen. Für JSX spricht

jedoch die deutlich bessere Lesbarkeit!

Diese Übersetzung in pures JavaScript kann entweder als Teil des Build-Prozesses, bei der Auslieferung

durch den Web-Server oder sogar erst im Client geschehen, wobei letztere Variante aus Performanz-

Gründen nur für Entwicklungsversionen zu empfehlen ist.

Um das von einer React-Komponente generierte HTML zu sehen zu bekommen, muss man sie in ein

Container-Element rendern. Das ist meist ein div-Element irgendwo auf der HTML-Seite mit einer ID:

<div id="container"/>

Um unsere HelloWorld-Komponente in dieses Element zu rendern, schreibt man anschließend (wieder

in JSX-Syntax):

ReactDOM.render(<HelloWorld/>, document.getElementById("container"));

Wenn dieser Code ausgeführt wird, wird der bisherige Inhalt des Zielelements entfernt und durch das

Resultat der render-Methode der Komponente ersetzt.

Das Ergebnis dieses Vorgangs ist in diesem Fall eine HTML-Seite mit folgendem Inhalt:

<div id="container"><div>Hello World!</div></div>

Die Nutzung von React erfordert in der jeweiligen Web-Site lediglich die Einbettung zweier Skripte.

Diese können z. B. von cloudflare bezogen werden:

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react-with-

addons.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react-

dom.min.js"></script>

React selbst hat keine weiteren Abhängigkeiten.

Page 4: Web-Entwicklung mit React - Cortex Brainware · 2016. 3. 30. · Web-Entwicklung mit React Eine Einführung in die Nutzung von React Zusammenfassung Die von Facebook veröffentlichte

React und .NET

Die Verwendung von React ist selbstverständlich mit allen Technologien zur Erstellung von Web-

Anwendungen nutzbar.

Alle in diesem Text erwähnten Beispiele sind als vollständige .NET Solutions verfügbar und können etwa

mit der Community-Edition von Visual Studio 2015 (oder neuer) ausprobiert werden. Die Projekte finden

Sie unter https://github.com/s-buss/ReactIntro.

Will man React in ASP .NET MVC nutzen, empfiehlt es sich je nach genutzter MVC-Version entweder das

NuGet-Paket React.Web.Mvc4 (für MVC 4 oder 5) oder React.Web.AspNet (ab MVC vNext bzw. 6)

einzubinden. Diese Pakete bieten eine On-The-Fly-Übersetzung von JSX-Dateien bei der Auslieferung an

die Clients an, so dass ein expliziter Build-Step zur Übersetzung nicht erforderlich ist. Außerdem

erlauben diese Pakete auch das Server-seitige Rendern von React-Komponenten. Das bedeutet, dass der

Server bereits das erzeugte HTML ausliefert. Das kann Vorteile bei der Geschwindigkeit des

Seitenaufbaus und für die Sichtbarkeit in Suchmaschinen bedeuten. Für Details sei auf die

Dokumentation von React und den genannten NuGet-Paketen verwiesen.

Komponenten mit Properties

Die Komponente aus dem vorherigen Abschnitt ist ziemlich uninteressant, da sie komplett statisch ist. Es

gibt keine Möglichkeit, Daten in die Komponente hineinzugeben, um die Ausgabe zu beeinflussen. Das

ändert sich durch Properties.

Jeder React-Komponente kann man bei der Verwendung beliebige sogenannte Properties mitgeben. Die

Werte der Properties sind einfache Werte wie Strings bzw. Zahlen oder beliebige JavaScript-Objekte

(Strukturen, Arrays, ...). In JSX werden Property-Werte syntaktisch wie HTML-Attribute übergeben.

Intern werden die Property-Werte in einem Feld namens props gespeichert. Auf die Properties einer

Komponente greift man deshalb innerhalb der render-Methode über this.props.propertyName zu.

Mit Properties sieht das Beispiel aus dem vorherigen Abschnitt vielleicht so aus:

var HelloWorld = React.createClass({

render: function() {

return (

<div className="hello" style={{ fontSize: "20px" }}>

Hello {this.props.name}!

</div>

);

}

});

ReactDOM.render(<HelloWorld name="John"/>,

document.getElementById("react-container"));

Hier ist zu erkennen, wie man Properties an eigene Komponenten wie HelloWorld übergibt. Unsere

HelloWorld-Komponente besitzt jetzt ein Property name, dem ein Wert zugewiesen kann bzw. muss,

wenn diese Komponente benutzt wird. Der Name wird in das erzeugte div-Element eingesetzt. Die

geschweiften Klammern erlauben die Einbettung beliebiger JavaScript-Ausdrücke in den Markup

innerhalb des return-Statements.

Page 5: Web-Entwicklung mit React - Cortex Brainware · 2016. 3. 30. · Web-Entwicklung mit React Eine Einführung in die Nutzung von React Zusammenfassung Die von Facebook veröffentlichte

In diesem Beispiel gibt es keine Deklaration der Properties der HelloWorld-Komponente. Die

Komponente erwartet einfach, dass bei der Verwendung ein String als Wert für das Property name

übergeben wird. Optional kann man aber auch in der Komponente deklarieren, welche Properties es

gibt und welche Typen sie haben. Der JSX-Compiler prüft dann die korrekte Verwendung der

Komponente zur Compile-Zeit. Wie das geht, ist unter

https://facebook.github.io/react/docs/reusable-components.html#prop-validation

zu sehen.

Ebenfalls kann man sehen, dass auch die vordefinierten Komponenten für HTML-Elemente wie <div>

Properties akzeptieren, die im Wesentlichen in HTML-Attribute umgewandelt werden. Dabei wird noch

einmal deutlich, dass es hier nicht um die „echten“ HTML-Elemente geht, sondern um React-

Komponenten gleichen Namens. In diesem Beispiel sind zwei Unterschiede sichtbar:

1. Anstelle des HTML-Attribut class verwendet man das Attribut className.

2. Das Property styles nimmt als Wert keinen String, sondern ein JavaScript-Objekt mit den

einzelnen CSS-Attributen als Eigenschaften. CSS-Attribute, die Minuszeichen enthalten wie font-

size werden dabei zudem über Eigenschaftsnamen in Camel-Case-Schreibweise angesprochen, z.

B. fontSize. Die doppelten geschweiften Klammern kommen von der Einbettung eines

JavaScript-Ausdrucks (das äußere Klammerpaar) in das Markup. Das innere Klammerpaar gehört

zum JavaScript-Objekt.

Der Code in der Render-Methode ist ganz normales JavaScript. Die einzige Erweiterung ist die HTML-

ähnliche Syntax für die Verwendung von Komponenten! Man kann deshalb Property-Werte und Inhalte

von Unterkomponenten auch in Variablen speichern und in das Ergebnis einsetzen. Das könnte

folgendermaßen aussehen:

var HelloWorld = React.createClass({

render: function() {

var c = "hello";

var s = {

fontSize: "20px"

};

var name = this.props.name;

return (

<div className={c} style={s}>Hello {name}!</div>

);

}

});

Die "Berechnung" der Werte darf natürlich beliebig kompliziert sein und die Variablennamen können

sprechender sein!

Properties sind aus Sicht der Komponente strikt schreibgeschützt. Eine Komponente sollte niemals

Werte in seinem props-Objekt ändern!

Page 6: Web-Entwicklung mit React - Cortex Brainware · 2016. 3. 30. · Web-Entwicklung mit React Eine Einführung in die Nutzung von React Zusammenfassung Die von Facebook veröffentlichte

Komponentenzustand und Ereignisbehandlung

Neben den Properties kennt jede React-Komponente auch einen Zustand (state). Anders als ihre

Properties darf und soll eine Komponente ihren Zustand ändern! In der Regel passiert das aufgrund von

Ereignissen, meist durch Nutzeraktionen. Ähnlich wie die Properties wird der Zustand einer Komponente

in einem JavaScript-Objekt abgelegt, in diesem Fall this.state.

Bei Zustandsänderungen kommt ein wichtiger Teil der React-Architektur zum Tragen. Ist eine

Komponente einmal gerendert, gibt es keine Möglichkeit, um das generierte virtuelle DOM explizit zu

verändern (z. B. neue Elemente hinzuzufügen oder vorhandene zu verändern). Den einzigen Weg, den

React als Reaktion auf Zustandsänderungen kennt, ist das erneute Rendern der Komponente(n). Das

klingt zunächst ineffizient, macht die Programmierung einer aktiven Komponente aber tatsächlich

extrem einfach.

Will man unsere HelloWorld-Komponente um einen Mouse-Over-Effekt erweitern, sieht das zum

Beispiel so aus:

var HelloWorld = React.createClass({

getInitialState: function() {

return { isHovered: false, dummy: 17 };

},

handleMouseEnter: function() {

this.setState({ isHovered: true });

},

handleMouseLeave: function () {

this.setState({ isHovered: false });

},

render: function () {

var className = "hello";

var additionalText = undefined;

if (this.state.isHovered) {

className = "hello hovered";

additionalText = <span>&nbsp;(hovered)</span>;

}

return (

<div className={className} style={{ fontSize: "20px" }}

onMouseEnter={this.handleMouseEnter}

onMouseLeave={this.handleMouseLeave}>

Hello {this.props.name}! {additionalText}

</div>

);

}

});

Die Methode getInitialState ist von React dafür vorgesehen, das Feld state einmalig zu füllen. Sie wird

vor dem ersten Rendern aufgerufen (sofern sie in der Komponentenklasse definiert wurde) und der

Rückgabewert wird in this.state gespeichert.

Page 7: Web-Entwicklung mit React - Cortex Brainware · 2016. 3. 30. · Web-Entwicklung mit React Eine Einführung in die Nutzung von React Zusammenfassung Die von Facebook veröffentlichte

handleMouseEnter und handleMouseLeave sind Event-Handler für die gleichnamigen Maus-Ereignisse.

Alles was sie tun, ist den Zustand der Komponente über die Methode setState zu modifizieren. Zu

beachten ist hier, dass die Methode den Zustand nicht komplett ersetzt, sondern nur die angegebenen

Werte überschreibt und alle anderen unverändert lässt. Der Wert von dummy bleibt in diesem Beispiel

also erhalten.

Die Methode render wurde gegenüber dem vorgehenden Beispiel so modifiziert, dass sie abhängig vom

Zustand isHovered unterschiedliche Klassen für das div-Element verwendet. Mit einem geeigneten

Stylesheet ändert das möglicherweise die Hintergrundfarbe.

Außerdem wird im Fall isHovered ein zusätzlicher Text in dem div-Element hinter der Begrüßung

dargestellt. Die Variable additionalText ist ein Beispiel dafür, wie Unterkomponenten optional

verwendet werden. Im Fall isHovered = false bleibt der Wert undefined und die Einbettung

{additionalText} wird ignoriert. Andernfalls enthält diese Variable eine Instanz der (eingebauten)

Komponente span, die in das von HelloWorld gerenderte HTML eingebettet wird.

Was passiert zur Laufzeit?

Zu Beginn wird die Komponente im Zustand isHovered = false gerendert. Sobald der Mauszeiger den

Bereich der Komponente betritt, wird die entsprechende Handler-Methode handleMouseEnter

aufgerufen. Das führt dazu, dass der Zustand auf isHovered = true geändert wird. Danach wird die

Komponente erneut gerendert und generiert dieses Mal ein anderes Markup. Umgekehrt passiert das

gleiche.

Nach dem jeweiligen Neurendern der Komponente aktualisiert React automatisch die HTML-Darstellung

der Komponente. Dabei stellt React fest, welche Teile des physikalischen DOM-Baums entfernt oder

verändert wurden oder hinzugekommen sind und nimmt die entsprechenden Veränderungen vor.

Dieser Vorgang heißt Reconciliation. Nach dem Abschluss der Reconciliation zeigt der Browser die

aktualisierte Seite.

Bei größeren Anwendungen mit großen, tief geschachtelten Komponenten können tatsächlich beide

Schritte (Rendering und Reconciliation) Performanz-kritisch sein. Für beide möglichen Engpässe bietet

React aber Mittel an, um die Performanz-Einbußen zu minimieren. In den folgenden Abschnitten

werden zwei grundlegende Techniken verwendet: das Verhindern unnötiger Renderings

(shouldComponentUpdate bzw. PureRenderMixin) sowie das Minimieren des Reconciliation-Aufwands

(durch das Property key).

Das Ergebnis ist eine wirklich leicht zu beherrschende Technik für die Erstellung von sehr

leistungsfähigen Web-Anwendungen.

Page 8: Web-Entwicklung mit React - Cortex Brainware · 2016. 3. 30. · Web-Entwicklung mit React Eine Einführung in die Nutzung von React Zusammenfassung Die von Facebook veröffentlichte

Ein größeres Beispiel

Auf GitHub finden Sie ein größeres Beispiel namens „04 – MovieList“. Dieses zeigt, wie eine etwas

komplexere Komponente aussieht. In diesem Beispiel geht es um die Liste aller 24 bislang erschienenen

offiziellen Bond-Filme. Zu allen Filmen liegen einige Daten in Form einer Liste von JavaScript-Objekten

vor.

Pro Film gibt es einen Eintrag mit Titel Erscheinungsjahr, dem Namen des Bond-Darstellers, einem

Verweis auf eine Bilddatei mit dem Filmposter des Films und einer kurze Handlungsübersicht1. Diese

Informationen sollen auf ansprechende Weise als Web-Seite dargestellt werden. Der Eintrag für den

ersten Film sieht wie folgt aus:

{

title: "Dr. No",

year: 1962,

bond: "Sean Connery",

poster: "http://image.tmdb.org/t/p/w90/utXgLvPouQaQj8qmJ0sUtxCacsi.jpg",

overview: "John Strangways, […]"

}

Der Einfachheit halber wird diese Liste im Beispiel nicht als JSON-Datei geladen, wie es wahrscheinlich in

einer echten Anwendung der Fall wäre. Stattdessen ist sie direkt als JavaScript-Datei (Scripts/Data.js) in

die Seite eingebunden.

In der Datei Scripts/BondMovieList.jsx finden Sie die Definition von zwei React-Komponenten. Die

Äußere von beiden (BondMovieList) stellt eine Liste von Filminfos dar. Sie verwendet eine innere

Komponente (BondMovie), die einen einzelnen Film darstellt. Das ist schon alles.

Die Komponente BondMovie hat zwei Properties: index gibt den Index des Films in der Liste aller Filme

an, movie enthält die Informationen über den darzustellenden Film. Die Komponente besteht eigentlich

nur aus einem Stück Markup, das in Zusammenarbeit mit einem geeigneten Style-Sheet eine Ausgabe

erzeugt, die etwa so aussieht:

1 Die Daten wurden aus Wikipedia (https://en.wikipedia.org/wiki/List_of_James_Bond_films) entnommen. Die

Bilder für die Poster stammen aus der TMDb (https://www.themoviedb.org).

Page 9: Web-Entwicklung mit React - Cortex Brainware · 2016. 3. 30. · Web-Entwicklung mit React Eine Einführung in die Nutzung von React Zusammenfassung Die von Facebook veröffentlichte

Etwas interessanter ist die Komponente BondMovieList:

var BondMovieList = React.createClass({

render: function () {

var movieList = this.props.movies;

var movieElems = movieList.map(function (movie, index) {

var key = movie.year;

return (

<BondMovie key={key} index={index} movie={movie}/>

);

});

return (

<div className="bond-movielist">{movieElems}</div>

);

}

});

Diese Komponente bekommt als Property movies eine ganze Liste von Filmeinträgen. Diese Liste wird in

eine Liste movieElems von Instanzen der Komponente BondMovie umgewandelt, wobei jeweils der

Listenindex und der einzelne Film wiederum als Properties übergeben werden.

Das Ergebnis ist schließlich ein div-Element, das die von BondMovie gerenderten einzelnen Filme

umschließt.

An dieser Stelle sind zwei Dinge interessant:

Erstens sei darauf hingewiesen, dass eine Komponente immer nur exakt ein Element zurückgeben darf.

Das ist eine Einschränkung von React. Ein einfaches return movieElems; würde nicht funktionieren, das

umschließende div ist notwendig.

Das zweite interessante Detail ist das zusätzliche Property key, das jedem BondMovie mitgegeben wird.

Dieses Property kann jeder Komponente übergeben werden und ist bei der Darstellung von Listen

wichtig. Die Vorgabe ist, jedem Element einen Schlüssel zuzuweisen, der das jeweilige Element eindeutig

(innerhalb der Liste bzw. seiner Vaterkomponente) identifiziert. Im Beispiel machen wir uns zunutze,

dass pro Jahr maximal ein Bond-Film erscheint und es deshalb als Schlüssel taugt.

Diese Zuordnung von eindeutigen Bezeichnern hilft React bei der Optimierung des Rendering-Prozesses,

genauer der Reconciliation. Es erlaubt, bei Aktualisierungen die Elemente der neuen Liste denen der

alten Liste zuzuordnen. Dadurch ist es möglich, Verschiebungen von Elementen der Liste zu erkennen

und das Rendering auf dazukommende Elemente zu beschränken. Mehr dazu folgt im nächsten

Abschnitt. Ohne diese Schlüssel ist das erneute Rendern von längeren Listen sehr ineffizient, da immer

die komplette Liste gerendert werden muss, auch wenn nur ein einziges Element hinzugekommen ist

oder entfernt wurde. React gibt deshalb eine Warnung auf der JavaScript-Konsole aus, wenn Listen ohne

key-Properties gerendert werden.

Mehr Details zu diesem Thema finden Sie unter

https://facebook.github.io/react/docs/reconciliation.html

Page 10: Web-Entwicklung mit React - Cortex Brainware · 2016. 3. 30. · Web-Entwicklung mit React Eine Einführung in die Nutzung von React Zusammenfassung Die von Facebook veröffentlichte

Hinzufügen von Nutzerinteraktion

Eine etwas erweiterte Variante des letzten Beispiels ist „05 - SortableMovieList“ (ebenfalls unter dem

oben genannten GitHub-Link zu finden). Wie der Name schon andeutet, wird der Code hier um die

Möglichkeit erweitert, die Liste umzusortieren.

Hier kommen Zustand und Ereignisbehandlung aus dem Abschnitt „ Komponentenzustand und Ereignisbehandlung“ zum Einsatz. Dieses Beispiel ist aber etwas realistischer.

Wieder werden die Ereignisse MouseEnter und MouseLeave dazu verwendet, die Hintergrundfarbe des

Elements zu verändern und zusätzliche Elemente einzublenden. In diesem Fall sind diese zusätzlichen

Elemente zwei Buttons, mit denen der Nutzer den Film in der Liste auf und ab bewegen kann.

Mit den notwendigen Erweiterungen werden beide Komponenten etwas länglich, so dass ab jetzt nur

noch die interessanten Ausschnitte dargestellt werden.

Der erste Unterschied zum statischen Beispiel ist dass die Liste ab jetzt veränderlich ist, also zum

Zustand der Komponente BondMovieList gehört. Von außen wird nur noch die initiale Liste bzw.

Sortierung als Property initialMovies übergeben. Die Methode getInitialState überträgt den Property-

Wert in den Zustand unter dem Namen movies:

getInitialState: function() {

return { movies: this.props.initialMovies };

}

Die React-Dokumentation weist eindrücklich darauf hin, dass die Duplizierung von Properties in den

State ein Anti-Pattern ist und ein Entwickler beides strikt voneinander trennen sollte. Die Initialisierung

der Zustands-Eigenschaften aus Properties ist aber explizit erlaubt. Wichtig ist, dass in der Komponente

immer nur die Liste aus dem state verwendet wird. Das sieht man z. B. in der geänderten render-

Methode. Dort steht jetzt:

[…]

var movieList = this.state.movies;

[…]

Diese Änderung reicht schon aus, um die Liste editierbar zu machen. Ein bisschen wird die

Implementierung der Umsortierung dadurch erschwert, dass die aktiven Elemente Buttons in der

Komponente BondMovie sind, ihre Verwendung aber eine Aktualisierung der umgebenden

BondMovieList sind. Von BondMovie aus besteht aber kein direkter Zugriff auf die Vaterkomponente.

Deshalb ist die Verwendung eines Callbacks notwendig.

Die eigentliche Manipulation der Liste ist als Methode in BondMovieList implementiert:

Page 11: Web-Entwicklung mit React - Cortex Brainware · 2016. 3. 30. · Web-Entwicklung mit React Eine Einführung in die Nutzung von React Zusammenfassung Die von Facebook veröffentlichte

moveMovie: function (oldIndex, newIndex) {

if (newIndex < 0 || newIndex >= this.state.movies.length) {

return;

}

var newList = this.state.movies.slice(0);

var tmp = newList[newIndex];

newList[newIndex] = newList[oldIndex];

newList[oldIndex] = tmp;

this.setState({ movies: newList });

}

Diese Methode verschiebt einen Film vom alten Platz oldIndex auf den neuen Platz newIndex, indem es

ihn mit dem Eintrag an der neuen Position vertauscht. Am Ende steht wieder ein Aufruf von setState,

der die neue Liste in den Zustand übernimmt und eine Aktualisierung durch erneutes Rendern auslöst.

Die beiden Richtungs-Buttons, die beim Mouse-Over über einen Film sichtbar werden, sollen jetzt die

Liste entsprechend manipulieren. Dazu übergibt BondMovieList ihre Methode als Property an

BondMovie:

<BondMovie key={key} index={index} movie={movie} onMove={component.moveMovie}/>

BondMovie registriert wiederum Event-Handler für das Click-Event seiner beiden Buttons. Diese Event-

Handler können auf das Property index zugreifen und die übergebene Methode mit entsprechenden

Parametern aufrufen.

moveUp: function () {

[…]

// Let the parent move this entry to a new position.

this.props.onMove(this.props.index, this.props.index - 1);

},

[…]

render: function () {

[…]

var buttonUp = undefined;

var buttonDown = undefined;

if (this.state.isHovered) {

[…]

buttonUp = <div […] onClick={this.moveUp}>[…]</div>;

buttonDown = <div […] onClick={this.moveDown}>[…]</div>;

}

return […];

}

Das Ergebnis dieser Bemühungen ist, dass tatsächlich ein Klick auf einen der erscheinenden Buttons den

Film um eine Position nach oben oder unten verschiebt.

Page 12: Web-Entwicklung mit React - Cortex Brainware · 2016. 3. 30. · Web-Entwicklung mit React Eine Einführung in die Nutzung von React Zusammenfassung Die von Facebook veröffentlichte

Technisch funktioniert das ganze wie gesagt dadurch, dass die Komponente BondMovieList ihren

Zustand ändert und die komplette Film-Liste neu rendert. Dabei wird für jedes BondMovie die render-

Methode aufgerufen, auch wenn sich an der Darstellung dieses Elements überhaupt nichts geändert hat.

Diese unnötigen Aufrufe von render können bei größeren Projekten lange dauern.

React bietet hier eine Eingriffsmöglichkeit zur Vermeidung unnötiger Render-Aufrufe. Eine Komponente

kann eine Methode namens shouldComponentUpdate (siehe hier) implementieren. Diese wird – sofern

vorhanden – vor jedem Aufruf von render aufgerufen. Falls sie false zurückgibt, verzichtet React auf das

Rendering der Komponente und geht davon aus, das letzte Ergebnis von render noch gültig ist. Wir

könnten hier zum Beispiel prüfen, ob der Film und sein Index unverändert sind. Übergeben werden das

neue props-Objekt und das neue state-Objekt, die mit den bisherigen Werten (this.props bzw. this.state)

verglichen werden können. Noch komfortabler geht das jedoch über ein Mixin. Das ist eine in

verschiedenen Komponenten wiederverwendbare Implementierung von Methoden.

Zur Vermeidung von unnötigen Renderings gibt es ein Add-On namens PureRenderMixin, das uns die

Arbeit des Vergleichs abnimmt und eine generische Implementierung für shouldComponentUpdate

liefert. Die Verwendung ist denkbar einfach:

var BondMovie = React.createClass({

mixins: [ React.addons.PureRenderMixin ],

[…]

};

Den Effekt kann man sehen, wenn man in der Beispiel-Solution die Konsole im Browser betrachtet. In

der render-Methode steckt eine einfache console.log-Anweisung, die bei jedem Aufruf der Methode

eine Zeile auf die Konsole schreibt. Ohne das Mixin wird die Methode bei jedem Verschieben eines Films

24-mal aufgerufen, da jeder Film der Liste neu gerendert wird. Mit dem Mixin passiert das nur noch 2-

mal, da die beiden vertauschten Filme ihren Index ändern. Für alle anderen Filme wird das Rendern

unterdrückt. Genau genommen kommen jeweils noch 4 Aufrufe von render dazu. Schuld daran ist das

Mouse-Over.

In der Methode shouldComponentUpdate liegt die Lösung vieler Performanz-Probleme von React-

Anwendungen. Schafft man es, unnötige render-Aufrufe zu vermeiden, ist React trotz des scheinbaren

Brute-Force-Ansatzes auch bei größeren Komponenten und Datenmengen sehr schnell.

Fazit

React kann die Behauptung vom Anfang des Textes tatsächlich einlösen. Das Programmiermodell von

React vereinfacht kompliziertere Manipulationen am DOM-Baum einer Seite, da sich für den

Programmierer jede Änderung nur als erneutes Rendern einer Komponente darstellt. Das verhindert die

Entstehung von komplexem Code für Manipulationen der Seite und reduziert die Wahrscheinlichkeit

von Fehlern. Mit den richtigen Hilfestellungen bleibt die Performanz dabei nicht auf der Strecke.