Webkrauts Logo

Webkrauts Webkrauts Schriftzug

- für mehr Qualität im Web

Web-Komponenten in Javascript erstellen

Einführung in React

Web-Komponenten in Javascript erstellen

Die Modularisierung in wiederverwendbare Komponenten ist ein beliebter Ansatz aus der Softwareentwicklung, der mit der zunehmenden Komplexität von Web-Anwendungen auch in der Web-Entwicklung üblich wird. Als Alternative zur »amtlichen« W3C-Lösung Web Components ist Facebooks React eine leistungsfähige Javascript-Lösung zur Erstellung von Komponenten.

Web-Anwendungen sind, auf ihren Kern reduziert, ein Mix aus HTML, CSS und JavaScript zur Darstellung eines Zustands von Datenobjekten als HTML im Browser. Das kann bei komplexeren Anwendungen mit aufwändigen Oberflächen schnell unübersichtlich werden. Es wimmelt dann von Event-Handlern im Code oder in einem Geflecht von JS-Dateien, um bei bestimmten Benutzer-Aktionen oder Änderungen von dargestellten Daten, Aktionen zur Modifikation der HTML-Oberfläche durchzuführen. Ganz zu schweigen von den über viele Dateien verteilten HTML- und CSS-Code-Elementen. Alle Webworker werden das schon zur Genüge »genossen« haben, als sie versuchten, in einer komplexen Webanwendung herauszufinden, warum etwas geschieht und so dargestellt wird wie es dargestellt wird.

Deshalb hätten Webworker gerne eine Möglichkeit zur Kapselung und Modularisierung von Oberflächenelementen. Denn reduziert man die Aufgabe von Oberflächenelemente im Browser auf ihre Kernaufgabe, ist diese im Grunde recht einfach: Auf Ereignisse warten, den Zustand des hinter der Oberfläche liegenden Datenobjekts ändern und darauf mit Änderung des DOMs reagieren. Und genau das leistet React.

React

React ist eine »Javascript-Bibliothek für das Erstellen von Benutzeroberflächen« (Zitat auf der Website) und wird von Facebook entwickelt. Leistungsfähige Anwendungen wie Instagram, diverse Facebook-Apps oder Githubs auf Web-Technik basierender Code-Editor Atom verwenden es.

React im Einsatz – Atom-Editor

Im Gegensatz zu bekannten Javascript-Frameworks wie AngularJS, Ember.js oder Backbone.js versteht sich React nicht als vollständiges »Web-Application-Framework«, sondern als Helfer bei der oben skizzierten Kernaufgabe der Web-Anwendung. Es kann daher mit beliebigen anderen Frameworks zusammenarbeiten. Die React-Entwickler sehen das laut React-Website so: »Lots of people use React as the V in MVC«. Also als »View«-Komponente, wenn die Anwendung nach dem in Webentwicklungsframeworks populären Model-View-Controller-Paradigma entwickelt wird.

React-Komponenten sind im Prinzip »schlaue« HTML-View-Templates mit Event-Handler und eigener Zustands-Verwaltung. Mit Hilfe der eingebauten XML-artigen Template-Sprache JSX (für »Javascript XML«) kann JS-Logik, HTML und sogar CSS in eine React-Komponente gekapselt und modular in der Web-Applikation eingesetzt werden.

Darin ist React, obwohl es technisch etwas völlig anderes ist, den im Webkraut-Adventskalender im Törchen 9 vorgestellten Web Components nicht unähnlich. Der oben beschriebene Drang zur Modularisierung und Kapselung von Oberflächenelementen zu Komponenten zeitigt durchaus unterschiedliche Lösungsansätze. Und während Web Components noch mehr oder weniger eine Zukunftstechnologie sind, sind React-Komponenten bereits hier und jetzt verfügbar, in allen Browsern bis hinunter zum IE9, mit Hilfe von es5-shim sogar noch im IE8.

Ein einfaches Beispiel

Damit genug der Vorrede, schauen wir uns das einmal im Code an. In dem auf der Website herunterladbaren Starter Kit findet ihr alles Notwendige, um mit React loslegen zu können. Die Syntax ist ein wenig gewöhnungsbedürftig, darum wollen wir diese mit überschaubaren Beispielen vorstellen.

Nach Einbinden der notwendigen Bibliotheken im Header könnt ihr eure ersten React-Komponenten schreiben. Das erste einfache Beispiel soll einen Absatz mit dem Text »Hallo Webkrauts« erstellen:

  1. <script type="text/jsx">
  2. var Greeter = React.createClass({
  3.   render: function() {
  4.     return (
  5.       <p>Hallo Webkrauts!</p>
  6.     )
  7.   }
  8. });
  9. React.render(
  10.   <Greeter/>,
  11.   document.getElementById('greeting')
  12. );
  13. </script>

Dieses Beispiel könnt ihr in JS Bin gleich ausprobieren.

In älteren Beispielen im Web findet sich stets »React.renderComponent« statt »React.render«, letzteres wurde erst in der frischen Version 0.12 eingeführt. Was als Warnung verstanden werden kann: React sieht sich selbst noch als Beta auf dem Weg zum 1.0-Release, es kommt daher noch häufiger zu Syntax-Änderungen von Release zu Release.

Wie »pures« Javascript kann React-Code mit dem script-Tag in das HTML geschrieben werden. Als Typ muss dabei aber »type=“text/jsx”« angegeben werden, die React-Bibliotheken (JSXTransformer.js) kennen diesen Typ und kompilieren den Code zur Laufzeit des Browsers in reines Javascript.

Die Umwandlung zur Laufzeit im Browser ist aber langsamer, darum sollte in Produktions-Code der React-Code mit den »react-tools« in fertiges JS kompiliert und ausgeliefert werden. React bietet dazu diverse Möglichkeiten zur Integration in Tooling-Umgebungen an.

Zurück zum Beispiel, mit React.createClass wird eine Klasse »Greeter« erzeugt. Deren Methode »render« enthält den JSX-Template-Code für das Rendern des Absatzes im HTML-Dokument. Mit der React.render-Methode wird die Komponente schließlich in die Seite eingebaut. Der erste Parameter, <Greeter/>, referenziert die React-Klasse in XML-artiger Syntax, der zweite Parameter bezeichnet das HTML-Element, in das hinein gerendert werden soll.

Virtual-DOM

Das unterscheidet sich, zumindest in so einem simplen Beispiel, im Grunde nur in der eigenwilligen Syntax von der Vorgehensweise mit jQuery und Konsorten; das eigentlich Interessante findet hinter den Kulissen statt:

React abstrahiert das DOM im Browser in einem »Virtual-DOM« (nicht zu verwechseln mit dem »Shadow-DOM« der Web Components) und führt alle Änderungen (wie das Einfügen des <p>… im Beispiel mit React.render) zunächst an diesem Virtual-DOM aus. Danach vergleicht React den Zustand des Virtual-DOM mit dem tatsächlichen DOM im Browser des Benutzers und führt die notwendige Änderungen in selbigem aus.
Das klingt umständlich, stellt sich in der Praxis aber als recht leistungsfähig heraus. Auf diese Art und Weise, sprich virtuelle Darstellung mit »echter« abgleichen und nur die Unterschiede ausführen, arbeiten z.B. auch 3D-Bibliotheken in der Spiele-Entwicklung.

Props

Selbstverständlich kann eine React-Komponente nicht nur im Template hinterlegte Daten ausgeben. Darum soll der »Greeter« nun um einen Parameter »name« erweitert werden, mit dem festgelegt werden kann, wer in der HTML-Seite begrüßt werden soll, in dem Fall die Welt:

  1. <script type="text/jsx">
  2. var Greeter = React.createClass({
  3.   render: function() {
  4.     return (
  5.       <p>Hallo {this.props.name}!</p>
  6.     )
  7.   }
  8. });
  9. React.render(
  10.   <Greeter name="Welt" />,
  11.   document.getElementById('greeting')
  12. );
  13. </script>

Für dynamische von außen zugängliche Daten kann jede React-Klasse »Properties«, in React kurz »props« genannt, verwenden. Die props werden im JSX-Template in geschwungenen Klammern gesetzt und mit »this.props.NAME« angesprochen. Der NAME wird dann als Parameter in der render-Methode benutzt.

Auch dieses Beispiel kann gleich in einem JS Bin ausprobiert werden.

State

Neben diesen von außen zugänglichen Properties kennen React-Klassen noch einen zweiten Typ von Datenstrukturen: den »State«. Während Props von außen gesetzt werden können, ist der State die innere Datenstruktur zur Verwaltung von Datenobjekten in den React-Klassen. Änderungen daran sollen nicht von außerhalb vorgenommen werden, sondern stets das Ergebnis eines Events der Klasse sein.

Wie das aussieht zeigt unser nächstes Beispiel. Es gibt unseren famosen »Greeter« mit »Hallo Welt« aus, nach einem Klick darauf soll sich der Text in »Hallo Webkrauts« ändern und umgekehrt (kann mit JS Bin ausgeführt werden):

  1. <script type="text/jsx">
  2. var Greeter = React.createClass({
  3.   getInitialState : function() {
  4.     return {
  5.       name : "Welt"
  6.     };
  7.   },
  8.   handleClick : function() {
  9.     if(this.state.name=="Welt"){
  10.       this.replaceState({
  11.         name : "Webkrauts"
  12.       });
  13.     }else{
  14.       this.replaceState({
  15.         name : "Welt"
  16.       });
  17.     }
  18.   },
  19.   render: function() {
  20.     var greeterCSS = {
  21.       backgroundColor: '#CACACA',
  22.       color: '#FFFFFF',
  23.       fontSize: '2em',
  24.       textAlign: 'center',
  25.       width: 400,
  26.       cursor: 'pointer'
  27.     };
  28.     return (
  29.       <p style={greeterCSS} onClick={this.handleClick}>Hallo {this.state.name}!</p>
  30.     )
  31.   }
  32. });
  33. React.render(
  34.   <Greeter />,
  35.   document.getElementById('greeting')
  36. );
  37. </script>

»name« ist nun kein prop mehr, sondern ein state. Mit der Methode »getInitialState« wird beim Initialisieren der Klasse ein Wert zugewiesen. Im JSX-Template wird mit »onclick« eine Methode als Click-Handler definiert, diese ändert den Wert für state.name. React ändert entsprechend das HTML im Virtual-DOM und als Resultat des Vergleichs zwischen Virtual-DOM und Browser-DOM wird das p-Element im Browser geändert.

JSX verwendet zur Definition der Events die »altbekannten« on..-Handler um einen Event-Handler zuzuweisen, die in letzter Zeit bekanntlich ein wenig aus der Mode gekommen sind. Davon darf man sich aber nicht täuschen lassen, React baut hinter den Kulissen ein ausgefeiltes auf die Eigenschaften des jeweiligen Browsers optimiertes Event-Handling auf.
De Fakto ist ein einziges Event-Handling aktiv (und nicht ein Event-Handling auf jedem DOM-Node), das jede durch .render hinzugefügte Komponente mit ihren Events automatisch berücksichtigt. Nach jedem Event wird dann zunächst das Virtual-DOM aktualisiert und erst nach dem Diff mit dem Browser-DOM die notwendigen Änderungen durchgeführt.

In der render-Methode findet sich auch ein Beispiel für das Kapseln des CSS für die React-Komponente. Das JS-Object GreeterCSS enthält diverse Definitionen für CSS-Eigenschaften, diese werden im ebenfalls »altbekannten« Inline-Stil im JSX-Template zugewiesen. React wandelt das JS-Objekt GreeterCSS zur Laufzeit in CSS um.

Der Vorteil davon liegt auf der Hand: Die Datenhaltung im State, das Event-Handling, die HTML-Struktur und die CSS-Eigenschaften dafür liegen in einer React-Komponente, die in sich abgeschlossen ist und so an beliebigen Stellen innerhalb der Web-Anwendung eingesetzt werden kann.

Praxis

Die Beispiele kratzen natürlich nur an der Oberfläche, weitere einfache Beispiele präsentiert ein Artikel bei tutorialzine.com. React-Komponenten können auch innerhalb von React-Komponenten verwendet werden, so dass es möglich ist, eine Bibliothek von wiederverwendbaren Oberflächenelementen zu erstellen.

Ein typisches Beispiel für eine sinnvolle React-Komponente wäre ein komplexes Formular, das auf Änderungen eines Formular-Elements die Daten in anderen Formular-Elementen ändern oder aktivieren/deaktivieren/erstellen muss und als Endergebnis per Submit dann diese Daten an jQuery oder ein anderes JS-Framework übergibt. Wer auf den Geschmack gekommen ist und tiefer einsteigen möchte möge das Tutorial auf der React-Website durcharbeiten.

Fazit

React ist der Gegenentwurf aus der Praxis zu den Web Components. Während letztere irgendwann nativ im Browser ausgeführt werden sollen, also maximale Nähe zum Browser suchen, strebt React nach dem genauen Gegenteil, nämlich der größtmöglichen Abstraktion vom Browser mit dem Virtual-DOM und seiner eigenen Event-Queue. Bis zu dem Schritt am Ende, bei dem der Zustand des Virtual-DOMs an das Browser-DOM angepasst wird, ist der Browser gar nicht im Spiel.

Die Bibliothek ist, schon durch ihre Herkunft aus der Massen-Website Facebook bedingt, gründlich auf Hochleistung optimiert und ordnet dem alles unter, wie die Entwickler selbst es ausdrücken: »React challenges a lot of conventional wisdom«. Das triggert natürlich Widerspruch bei so manchem aus der in der Frontend-Welt starken »Puristen-Fraktion«. Wen so eine Diskussion interessiert möge sich eine Diskussion zum Thema bei Programmers Stackexchange anschauen.

Egal ob Web Components oder React oder ein komplettes JS-Framework – bei komplexeren Anwendungen, die performant, wartbar und zukunftsfähig sein sollen, führen große JS-Dateien voller jQuery-Event-Bindings auf die Dauer nicht zum Erfolg. Wenn es darum geht, ein Werkzeug oder Framework auszusuchen, solltet ihr React durchaus in Erwägung ziehen.

Die Kommentare sind geschlossen.