Nils Hartmann ist freiberuflicher Softwareentwickler, -architekt, Trainer und Coach. Er hat langjährige Erfahrung in der Entwicklung mit Java sowie JavaScript/TypeScript, ist Autor von Fachartikeln und unterstützt Teams mit Trainings und Coaching beim Einstieg in JavaScript und die Entwicklung von modernen Webanwendungen. Mehr unter: https://nilshartmann.net
Oliver Zeigermann ist Entwickler, Architekt, Berater und Coach aus Hamburg. Er hat über Jahrzehnte in vielen unterschiedlichen Sprachen und mit vielen Technologien und Ansätzen Software entwickelt. Er ist Autor zahlreicher Fachbücher im JavaScript und React-Bereich, sowie Experte für Machine und Deep Learning. Mehr unter: http://zeigermann.eu/
|
Zu diesem Buch – sowie zu vielen weiteren dpunkt.büchern – können Sie auch das entsprechende E-Book im PDF-Format herunterladen. Werden Sie dazu einfach Mitglied bei dpunkt.plus+: www.dpunkt.plus |
Grundlagen, fortgeschrittene Techniken
und Praxistipps – mit TypeScript und Redux
2., überarbeitete und erweiterte Auflage
Nils Hartmann, Oliver Zeigermann
Lektorat: René Schönfeldt
Projektkoordinierung/Lektoratsassistenz: Anja Weimer
Copy-Editing: Ursula Zimpfer, Herrenberg
Satz: Gerhard Alfes, mediaservice, Siegen, www.mediaservice.tv
Herstellung: Stefanie Weidner
Umschlaggestaltung: Helmut Kraus, www.exclam.de
Bibliografische Information der Deutschen Nationalbibliothek
Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.d-nb.de abrufbar.
ISBN: |
|
978-3-86490-552-0 |
|
978-3-96088-419-4 |
|
ePub |
978-3-96088-420-0 |
mobi |
978-3-96088-421-7 |
2., überarbeitete und erweiterte Auflage 2020
Copyright © 2020 dpunkt.verlag GmbH
Wieblinger Weg 17
69123 Heidelberg
Hinweis:
Dieses Buch wurde auf PEFC-zertifiziertem Papier aus nachhaltiger Waldwirtschaft gedruckt. Der Umwelt zuliebe verzichten wir zusätzlich auf die Einschweißfolie.
Schreiben Sie uns:
Falls Sie Anregungen, Wünsche und Kommentare haben, lassen Sie es uns wissen: hallo@dpunkt.de.
Die vorliegende Publikation ist urheberrechtlich geschützt. Alle Rechte vorbehalten. Die Verwendung der Texte und Abbildungen, auch auszugsweise, ist ohne die schriftliche Zustimmung des Verlags urheberrechtswidrig und daher strafbar. Dies gilt insbesondere für die Vervielfältigung, Übersetzung oder die Verwendung in elektronischen Systemen.
Es wird darauf hingewiesen, dass die im Buch verwendeten Soft- und Hardware-Bezeichnungen sowie Markennamen und Produktbezeichnungen der jeweiligen Firmen im Allgemeinen warenzeichen-, marken- oder patentrechtlichem Schutz unterliegen.
Alle Angaben und Programme in diesem Buch wurden mit größter Sorgfalt kontrolliert. Weder Autor noch Verlag können jedoch für Schäden haftbar gemacht werden, die in Zusammenhang mit der Verwendung dieses Buches stehen.
5 4 3 2 1 0
Teil IEinstieg
1Einleitung
1.1Was ist React?
1.2Warum React?
1.3Beziehung zu anderen Technologien
1.4Vergleich mit anderen Webtechnologien
1.5Wie man dieses Buch benutzt
1.6Voraussetzungen für dieses Buch
1.7Änderungen gegenüber der ersten Auflage
1.8Website zum Buch
1.9Danksagungen
2Schnelldurchgang – React im Überblick
2.1Zusammengefasst: Unterschiede zwischen Hooks- und Klassen-API
2.2Ein React-Projekt beginnen mit Create React App
2.3Zusammenfassung
3Die Beispielanwendung: »Vote as a Service«
3.1Die Beispielanwendung installieren und ausführen
3.2Fachliches Modell
3.3Die Anwendung schrittweise entwickeln
3.4Zusammenfassung
Teil IIReact
4Eine React-Komponente
4.1Hands-on: eine Komponente
4.2React-Komponenten in der Übersicht
4.3Hooks
4.4Zustand verwalten mit useState
4.5Ereignisse und Event Handler
4.6JSX zur Beschreibung der UI
4.7Rückgabewerte von Komponenten
4.8Einhängen der Anwendung in den DOM
4.9Arbeiten mit CSS
4.10Zusammenfassung
5Arbeiten mit Komponentenhierarchien
5.1Hands-on: Hierarchien von Komponenten
5.2Kommunikation zwischen Komponenten
5.3Das »Render Properties«-Pattern
5.4Performance-Optimierung: Caching von Werten mit useMemo
5.5Performance-Optimierung: Rendern vom Komponenten unterdrücken
5.6Performance-Optimierung: Code-Splitting mit React.lazy und Suspense
5.7Der React Strict Mode
5.8Zusammenfassung
6Formulare mit React
6.1Hands-on: ein Editor für Umfragen
6.2Hintergrund: Databinding
6.3Controlled Components
6.4Uncontrolled Components
6.5Auf native DOM-Elemente zugreifen: das ref-Property
6.6Komplexen Zustand mit useReducer verwalten
6.7Zusammenfassung
7Arbeiten mit Seiteneffekten: asynchrone Serverzugriffe
7.1Hands-on: Serveranbindung
7.2Seiteneffekte mit useEffect
7.3Code wiederverwenden mit Custom Hooks
7.4Server-Requests mit useState und useReducer
7.5Ausblick: Daten laden mit Suspense
7.6Zusammenfassung
Teil IIIÜber React hinaus
8React-Anwendungen testen
8.1Hands-on: Testen mit Jest und React Testing Library
8.2Überblick: React-Anwendungen testen
8.3React-Test-Bibliotheken
8.4Snapshot Testing
8.5Zusammenfassung
9Der React Router
9.1Hands-on: der React Router im Schnelldurchgang
9.2Anpassungen an der Vote-Anwendung
9.3Links und Routen
9.4Navigation über die History
9.5Authentifizierung
9.6Die React Context API
9.7Lazy Loading mit dem React Router
9.8Testen
9.9Zusammenfassung
10Externes Statemanagement mit Redux
10.1Motivation
10.2Hands-on: eine Redux-Anwendung
10.3Redux in der Vote-Anwendung
10.4Arbeiten mit dem globalen Zustand
10.5Asynchrone Actions
10.6Alternative zu Hooks: die connect-Funktion
10.7Integration von Redux und React Router
10.8Testen von Redux-Anwendungen
10.9Exkurs: Codestruktur von großen React-Anwendungen
10.10Alternative zu Redux: MobX
10.11Zusammenfassung
11React-Anwendungen mit TypeScript
11.1Hands-on: eine React-Anwendung mit TypeScript
11.2TypeScript in React-Anwendungen
11.3React-Komponenten mit TypeScript
11.4Der React Router mit TypeScript
11.5Redux
11.6Zusammenfassung
12GraphQL mit dem Apollo Client für React
12.1Hands-on: ein GraphQL-Client
12.2GraphQL in der Vote-Anwendung
12.3Mutations
12.4Der Apollo Client Cache
12.5GraphQL für externes Statemanagement?
12.6Der Apollo React Client mit TypeScript
12.7Zusammenfassung
Anhang
AServerseitiges Rendern mit React
A.1Ein Beispiel
A.2Gründe für serverseitiges Rendern
A.3Serverseitiges Rendern im Überblick
A.4Herausforderungen
A.5Asynchrones Datenladen mit Redux und dem React Router
BKomponenten als Klassen
B.1React-Komponenten als ES6-Klasse
B.2Methoden-Binding für Event Handler
B.3Zugriff auf native DOM-Elemente
B.4Arbeiten mit Seiteneffekten
B.5Beispiel: Error Boundaries
B.6Klassenkomponenten mit TypeScript
CEinführung in ES.Next
C.1Einleitung
C.2Block-Scope
C.3Template Strings
C.4Destructuring
C.5Klassen
C.6Vererbung
C.7Erweiterte Objekt-Literale
C.8Module, Exporte und Importe
C.9Arrow-Funktionen
C.10Default- und Rest Parameter
C.11Spread-Operator für Arrays
C.12Object.assign und Spread-Operator bei Objekten
C.13Promises
C.14async/await
C.15Generatorfunktionen
C.16Die fetch-API
DEinführung in TypeScript
D.1Motivation
D.2Die Sprache TypeScript
D.3Grundlagen des TypeScript-Typsystems
D.4Externe Typbeschreibungen
EÜbersicht GraphQL
E.1Abfragen
E.2Das Schema: Beschreibung der API
Index
React1 ist eine Open-Source-JavaScript-Bibliothek, mit der du Webanwendungen, sogenannte Single-Page-Anwendungen (kurz SPAs), erstellen kannst. Die Bibliothek wird von Facebook entwickelt und sowohl für facebook.com als auch für Instagram benutzt. Aber auch darüber hinaus ist React sehr weit verbreitet und wird zum Beispiel von Netflix, Airbnb, Twitter oder der Online-Ausgabe des Wall Street Journals verwendet. Da React kaum Bedingungen an seine Umgebung stellt, ist es sehr flexibel einsetzbar. So gibt es auch Webseiten, die React nur für einige interaktive Teile ihres Angebots verwenden.
Single-Page-Anwendungen
Single-Page-Anwendungen (SPAs) zeichnen sich dadurch aus, dass sie vollständig auf dem Client, also im Browser, laufen. Sämtliche Interaktionen werden auf dem Client bearbeitet und die Darstellung der Seite wird mittels JavaScript erzeugt bzw. aktualisiert, um eine möglichst flüssige Darstellung zu erreichen. Mit dem Server werden JavaScript-Code, statische Assets (Bilder, Fonts etc.) und Daten ausgetauscht, aber kein HTML-Code. Zur Entwicklung von Single-Page-Anwendungen haben sich spezialisierte Frameworks und Bibliotheken (in erster Linie React, Angular, Vue oder Web Components) herausgebildet, die von der zugrunde liegenden DOM-API abstrahieren und die Entwicklung dieser Anwendungen vereinfachen.
Im Gegensatz zu SPAs findet bei serverseitig gerenderten Websites und Anwendungen (auch »klassische Webanwendungen« genannt) bei Interaktionen ein Server-Roundtrip statt, bei dem fertiger HTML-Code zurückgeliefert wird. Aus diesem Grund eignet sich dieser Ansatz nur für zumeist statische Websites, auch wenn diese mit JavaScript an einzelnen Stellen um interaktive Features erweitert werden können.
Den Kern von React bilden Komponenten und ihre Komposition zu einer Anwendung. Durch eine solche Komposition wird bestimmt, was dargestellt werden soll oder – aus einer anderen Perspektive – wie man den Zustand einer Anwendung in ihre Darstellung transformiert. Beispiele für den Zustand einer Anwendung können fachliche Dinge sein, wie die Anzahl ungelesener Nachrichten, ein Blogpost, der gerade in der Anwendung bearbeitet wird, oder der zurzeit angemeldete User. Aber auch technische Dinge, wie die Informationen, welches Menü gerade aufgeklappt oder welcher Eintrag in einer Combobox ausgewählt ist, sind Zustand der Anwendung.
Der Kern von React ist übrigens losgelöst vom Web: React kann in unterschiedlichen Szenarien funktionieren, so auch in nativen Anwendungen (zum Beispiel iOS oder Android).
In diesem Buch werden wir uns aber auf die Webentwicklung beschränken und daher auch davon ausgehen, dass du eine Webanwendung mit React bauen willst. Eine solche Anwendung wird früher oder später im DOM des Browsers – der Objektrepräsentation der dargestellten Elemente – gerendert werden. Dazu gibt es zwei Möglichkeiten. In der Regel wird die Anwendung auf Clientseite, also im Browser, gerendert. Du kannst deine Anwendung aber zusätzlich auf dem Server rendern lassen, sofern du dort eine JavaScript-Engine laufen lässt. Dann wird auf dem Server fertiger HTML-Code erzeugt, der zum Browser geschickt wird und dort vom Browser nur noch in den DOM umgewandelt und angezeigt werden muss. Von da an werden alle Updates im Browser gerendert. Das ist sehr praktisch zum Beispiel für eine schnelle erste Anzeige der Anwendung.
React-Anwendungen werden in Komponenten aufgeteilt. Eine Komponente enthält alles Notwendige, um sich darzustellen. Dabei trennt React nicht zwischen Template und Logik; sowohl UI und Logik sind in der Komponente enthalten. Als Ersatz für das Template wird in React der UI-Code direkt in den JavaScript-Code einer Komponente geschrieben. Das geschieht mit der React-eigenen Spracherweiterung JSX, die es ermöglicht, HTML-artigen Code in JavaScript einzubinden.
Ohne an dieser Stelle schon in die Details zu gehen, könnte eine einfache Komponente, die in React als Funktion implementiert werden kann, wie folgt aussehen:
import React from "react";
export default function HelloMessage() {
return <h1>Hello, World</h1>;
}
Wenn diese Komponente in deiner Anwendung verwendet wird, sorgt React dafür, dass ein h1-Element in den DOM eingebaut wird, das den String »Hello, World« beinhaltet.
»UI as a Function«
Du siehst an dieser Stelle ein weiteres, wichtiges Konzept von React: Komponenten werden ausschließlich deklarativ beschrieben. Eine Komponente gibt demnach immer nur genau die UI zurück, die dargestellt werden soll. Man spricht daher von »UI as a Function« in der React-Entwicklung, da – genau wie bei einer mathematischen Funktion – zu demselben Eingabeparameter (React: Zustand) immer derselbe Wert (React: UI) zurückkommt.
Zur Laufzeit kümmert sich React dann darum, dass auch der DOM im Browser entsprechend angepasst wird – und zwar unabhängig davon, wie der DOM zuvor aussah. Die einzelnen Übergänge von einer UI zur nächsten, also das jeweilige Aktualisieren des DOM im Brower, übernimmt React für dich und geht dabei sehr effizient und optimiert vor. Funktionen zum Erzeugen oder Löschen von Elementen (wie beispielsweise createElement oder createAttribute aus der DOM-API) brauchst du in React nicht.
Durch die deklarative Programmierung entfällt eine Menge Komplexität und Fehleranfälligkeit, die aus anderen Ansätzen bekannt sind, da eine wesentliche Fehlerquelle, die diversen Übergänge innerhalb einer Anwendung, nicht implementiert werden müssen. Auch das Testen von Komponenten wird dadurch sehr einfach. In deinem Test übergibst du deiner Komponente ihre Parameter und prüfst hinterher, dass die richtige UI zurückgeliefert wird – genau wie bei einer »normalen« Funktion, nur dass du UI-Elemente überprüfst und keine numerischen oder anderen Werte.
Eigenschaften einer Komponente
Im Folgenden sind die Eigenschaften einer Komponente zusammengefasst:
In diesem Abschnitt möchten wir dir in aller Kürze Gründe nennen, warum man sich aus unserer Sicht mit React beschäftigen sollte und warum wir glauben, dass React eine sehr gute Bibliothek ist.
React hat eine überschaubare API und lässt sich sehr schnell erlernen. Das Architekturmodell hinter React, in dem der Anwendungszustand zentralisiert gehalten wird und die Daten nur in eine Richtung fließen, macht auch große Anwendungen noch gut verständlich und nachvollziehbar.
Die Einführung von Änderungen an der React-API erfolgt sehr behutsam. Inkompatible Änderungen werden bereits frühzeitig gut kommuniziert und die Abschaltung von APIs erfolgt erst, wenn es Ersatz dafür gibt. Trotz des relativ konservativen Releasezyklus werden aber beständig neue Features eingebaut. Ein gutes Beispiel dafür ist das derzeit (Stand Ende 2019) aktuelle Major-Release 16 von React, das bereits im September 2017 veröffentlicht wurde2 und jetzt also schon über zwei Jahre (!) aktiv ist. Diese Stabilität bedeutet allerdings nicht, dass keine neuen Features hinzukommen – im Gegenteil! Innerhalb dieses Major-Release sind diverse grundlegende neue Funktionalitäten hinzugekommen, etwa die Hooks-API, die wir in diesem Buch ganz besonders betrachten werden. Diese Änderungen waren allerdings alle abwärtskompatibel, sodass man sie in seiner bestehenden Anwendung einsetzen konnte, aber nicht musste. Du wirst also nicht alle paar Monate oder gar Wochen zu Updates deiner Anwendung gezwungen.
React konzentriert sich im Wesentlichen auf die Verwaltung des Zustands deiner Anwendung und insbesondere dessen Darstellung. Dabei macht React nur sehr wenige Annahmen über seine Umgebung, sodass die Bibliothek sich auch sehr gut in bestehenden Projekten und Websites einsetzen lässt und eine sanfte Migration bereits existierender Anwendungen erlaubt. Außerdem kannst du deinen Code so strukturieren, dass UI-unabhängige Logik von React getrennt implementiert wird und somit auch in anderen Projekten mit anderen Technologien weiterverwendet werden kann.
Um React herum ist bereits ein sehr lebendiges Ökosystem mit weiteren Tools und Bibliotheken für diverse Einsatzszenarien entstanden. Obwohl React nur ein eine UI-Bibliothek ist, musst du in deinem Projekt also nicht bei »null« anfangen, wenn du z.B. einen Router benötigst. In Teil III dieses Buchs gehen wir auf einige dieser Bibliotheken ein.
Es gibt für React sehr gute Tools zur Entwicklung, nach dem Motto: ohne gute Tools keine guten Anwendungen. Dazu zählen zum Beispiel die React Developer Tools für Chrome und Firefox, ein Kommandozeilen-Werkzeug zum Erzeugen neuer React-Projekte (Create React App) sowie sehr gute Unterstützung in allen populären Editoren und IDEs.
React ist sehr weit verbreitet und kommt auf vielen großen und kleinen Websites und Anwendungen im Internet zum Einsatz (neben Facebook zum Beispiel auch bei Netflix, Jira oder Microsoft Outlook) und auch als Lösung für In-House-Anwendungen im Intranet wird React gerne benutzt. Zur Stabilität von React trägt bei, dass neue Features in der Regel zunächst auf der riesigen facebook.com-Codebasis getestet und erst danach als Beta- und dann als finale Version veröffentlicht werden.
React hilft dir, Anwendungen für das Web zu bauen. Dabei ist React selten ganz allein im Einsatz. Insbesondere brauchst du für eine komplette Anwendung zumindest noch:
In größeren Anwendungen kommen meistens noch hinzu:
Die dazu passenden Techniken wollen wir nun kurz beleuchten.
Wie du gesehen hast, brauchen wir zwingend einen Compiler, wenn wir JSX nutzen wollen, denn kein Browser unterstützt den JSX-Code nativ und wird es vermutlich auch nie tun. Zum Übersetzen von JSX ist Babel3 das empfohlene Werkzeug. Babel ist in der Lage, neben JSX die jeweils aktuellen und vielfach auch die kommenden JavaScript-Sprachfeatures, als ES.Next bezeichnet, nach ES5 zurückzuübersetzen, bis diese von allen Browsern unterstützt werden, für die du deine Anwendung zur Verfügung stellen willst.
ES5, ES6, ES.next, ... Historie der JavaScript-Sprachversionen
Wir beziehen uns in diesem Buch auf unterschiedliche Versionen von JavaScript. Unterschiedliche Begriffe können dabei leicht zu Verwirrung führen.
Zuerst zum Unterschied zwischen ECMAScript und JavaScript: ECMAScript ist die Spezifikation der Sprache, die von der Organisation Ecma International veröffentlicht wird. JavaScript ist die Implementierung dieser Spezifikation. In der Praxis spielt dieser Unterschied kaum eine Rolle, und so werden – wenn es um die Benennung einer Version geht – »JavaScript« und »ECMAScript« häufig synonym verwendet.
Von der Spezifikation der Sprache gibt es unterschiedliche Versionen. Bis Juni 2015 war ECMAScript 5 (kurz: ES5) die aktuellste Version, die zu dem Zeitpunkt auch von praktisch allen Browsern unterstützt wurde. Das ist auch der Grund, warum diese Version häufig noch als Zielversion beim Kompilieren verwendet wird (der Internet Explorer 11 zum Beispiel unterstützt weiterhin fast keine neueren JavaScript-Features).
Im Juni 2015 wurde dann der Nachfolger von ES5 veröffentlicht, der häufig als ES6 bezeichnet wird, offiziell aber ECMAScript 2015 heißt. Die Begriffe ECMAScript 6, ES6 und ECMAScript 2015 beziehen sich auf dieselbe Sprachversion. Mit dieser Version gab es sehr viele neue Sprachfeatures (wie Modulsystem, Klassen, Promises, Block Scoping mit let und const, Arrow-Funktionen etc.), sodass man dieses JavaScript auch als »modernes JavaScript« bezeichnet. Die Lern- und Adaptionskurve für dieses Release war und ist dementsprechend hoch.
Aus diesem Grund wird seit 2015 regelmäßig einmal pro Jahr eine neue Sprachversion veröffentlicht (ES5 ist bereits 2009 erschienen), die dafür weniger Features enthält. Diese Versionen werden nach dem Jahr ihres Erscheinens benannt, häufig aber auch noch als ES7, ES8 etc. bezeichnet.
Dazu kommt noch der Begriff ES.Next. Dieser bezeichnet die jeweils kommende, noch unveröffentlichte Version (in Babel kannst du beispielsweise einstellen, dass du ES.Next-Features in deinem Code verwenden und kompilieren möchtest).
Die von uns verwendeten neuen Konzepte ab ES6 haben wir zusammengefasst im Anhang C erläutert. Im React-Umfeld ist es gängig, neue und teilweise auch unveröffentlichte Sprachfeatures recht schnell einzusetzen, was dank Babel auch kein großes Problem ist.
Modul-Loader
Wir strukturieren unsere Anwendung mit ES6-Modulen. Diese und ES6-Imports brauchen aber einen Modul-Loader (auch Bundler genannt), der Abhängigkeiten auflöst, da der Browsersupport für ES6-Imports noch nicht ausreichend ist. Mit Webpack4 und Browserify5 stehen uns hier zwei weitverbreitete Werkzeuge zur Verfügung. Beide lösen ES6-Importe auf und erzeugen je nach Konfiguration eine oder mehrere Ausgabedateien mit allen benötigten Abhängigkeiten. Webpack ist weit verbreitet und kommt auch bei Projekten zum Einsatz, die mit dem offiziellen React-Tool Create React App angelegt wurden.
Code-Splitting
Webpack unterstützt zudem Code-Splitting, das bedeutet, es kann deinen Code im Build in mehrere kleinere Ausgabedateien zerteilen, sodass der Browser initial nicht deine ganze Anwendung laden und interpretieren muss, sondern nur das, was zu einem Zeitpunkt wirklich benötigt wird. Code-Splitting wird auch von React unterstützt; mehr dazu findest du in Kapitel 5.6.
Typensystem für JavaScript
Mit TypeScript6 hat Microsoft eine getypte Erweiterung von JavaScript geschaffen. Du kannst damit für jeden Parameter, jedes Property und jede Variable einen Typ angeben, außerdem kannst du die Struktur von Objekten mit Interfaces beschreiben. Solche Typannotationen haben viele Vorteile. Neben der besseren Lesbarkeit kann dich auch die IDE besser unterstützen. Durch Typannotationen wird auch in der JavaScript-Welt verlässliches Refactoring, Codeanalyse und Code-Completion möglich.
Gerade für größere Projekte, die über einen längeren Zeitraum laufen, halten wir einen Type-Checker für unumgänglich.
TypeScript-Compiler
Microsoft liefert auch gleich einen Compiler mit, der diese Typannotationen checkt und in ES5-Code (oder wahlweise sogar ES3) zurückübersetzt. Der übersetzte Code bleibt dabei lesbar. Da dieser Compiler ebenfalls JSX unterstützt, kannst du den TypeScript-Compiler auch als Alternative zu Babel verwenden.
Man kann diesen Stil der Typannotationen aber auch ohne den TypeScript-Compiler verwenden. Babel ist in der Lage, diese Annotationen herauszufiltern oder per Plug-in auch in der Ausgabe als Kommentar beizubehalten. Als Checker dient dann z.B. die IDE (WebStorm7 und Visual Studio Code8 haben einen sehr guten Support dafür) oder andere Kommandozeilen-Werkzeuge. In Kapitel 11 zeigen wir, wie du TypeScript in deiner React-Anwendung einsetzen kannst.
Ein weiteres Beispiel eines solchen Werkzeugs ist Flow9, das ebenfalls von Facebook entwickelt wird. Flow übersetzt das annotierte JavaScript nicht – das macht ja wie erwähnt bereits Babel –, sondern führt lediglich eine Überprüfung der Typen durch.
Sourcecode formatieren mit Prettier
Prettier10 ist ein Tool zum Formatieren von JavaScript-, TypeScript- und anderem Sourcecode, das in der React-Community eine hohe Verbreitung erfahren hat. Es gibt dafür Integrationen in zahlreiche IDEs und andere Tools. Die Idee hinter Prettier ist, dass unabhängig davon, wer mit welchem Tool den Sourcecode editiert, dieser immer gleich formatiert ist und somit zum Beispiel »überflüssige« Diffs durch unterschiedliche Formatierungen in der Versionsverwaltung vermieden werden.
Auch wenn Prettier nicht dazu gedacht ist, Fehler im Code zu finden, gibt es doch manchmal einen Hinweis darauf, dass sich Syntaxfehler eingeschlichen haben. Wenn der Code beim Speichern nicht automatisch formatiert wird, ist die Wahrscheinlichkeit hoch, dass sich irgendwo ein Syntaxfehler (fehlende Klammer o.Ä.) eingeschlichen hat.
URLs auf Komponenten abbilden
Auch in Single-Page-Anwendungen sollte das Navigieren über die URL des Browsers sowie des Back-Buttons funktionieren. Das Konzept dazu heißt Router: Dieser setzt einerseits die URL in der Navigationszeile des Browsers, sobald ein anderer Anwendungsteils aufgerufen wird. Andererseits kann der Router die zur URL passenden Komponenten ermitteln und rendern lassen.
Der React Router11 ist nur eine von vielen Router-Implementierungen, die mit React benutzt werden können. Allerdings hat er sich als De-facto-Standard etabliert. Daher werden wir dem React Router auch das komplette Kapitel 9 in unserem Buch widmen.
Architekturmodell für React-Anwendungen
Flux12 ist ein von Facebook entwickeltes Architekturmodell, das beschreibt, wie mit React große Anwendungen gebaut werden können. Es definiert dazu ein Anwendungsmodell, bei dem Daten immer nur in eine Richtung durch die Anwendung fließen und dabei einen Kreislauf beschreiben. Das Modell ist weder auf React beschränkt noch ist es Bestandteil von React. Es gibt eine ganze Reihe von Frameworks, die die Flux-Architekturidee ausimplementieren. Die prominenteste Implementierung, die zumindest stark von dieser Idee inspiriert ist, ist Redux (siehe folgenden Abschnitt).
Redux13 ist ein Werkzeug zum »externen Statemanagement«, mit dem du den Zustand deiner Anwendung verwalten kannst, auch wenn diese sehr groß wird. Es ist inspiriert von der Flux-Architektur und bringt eine Reihe von Architekturvorgaben mit. So wird der Zustand der Anwendung an einer einzigen zentralen Stelle gehalten und die Verarbeitung (Logik) geschieht durch pure Funktionen – sogenannte Reducer. Redux stellen wir dir in Kapitel 10 vor.
Das Aufsetzen eines neuen React-Projekts ist aufwendig, da eine ganze Reihe von Tools, insbesondere für den Build, notwendig ist. Das Konfigurieren und Pflegen des Tool-Stacks mit allen Abhängigkeiten kann einen nicht unerheblichen Aufwand auch während der Projektlaufzeit darstellen.
Um dieses Problem zu umgehen, gibt es das Kommandozeilentool Create React App14, mit dem du ein neues Projekt anlegen kannst. In diesem Projekt sind alle wichtigen Abhängigkeiten und das Tooling bereits eingetragen und vorkonfiguriert, sodass du sofort mit der Entwicklung beginnen kannst. Die Konfigurationen der verwendeten Tools (zum Beispiel für den Produktionsbuild), die dann für dein Projekt eingesetzt werden, entsprechen den React-Best-Practices und werden ständig erweitert und verbessert. Du kannst die Versionen der Konfiguration jederzeit in deinem Projekt aktualisieren, um die neuesten Features zu bekommen.
Das Tool Create React App stellen wir dir in Abschnitt 2.2 vor.
Entwickertools für Chrome und Firefox
Für die Entwicklung von React-Anwendungen stehen die React Developer Tools zur Verfügung15. Dabei handelt es sich um eine Erweiterung für die Entwicklertools des Chrome- und Firefox-Browsers.
Die React Developer Tools zeigen in einem eigenen Tab die React-Komponenten einer Webseite sehr übersichtlich mitsamt ihren Properties und des aktuellen Zustands an. Die aktuellen Werte lassen sich darüber ebenfalls verändern, sodass du schnell ausprobieren kannst, wie sich deine Komponente mit anderen Properties verhalten würde.
Neben React gibt es eine ganze Reihe weiterer Webtechnologien. Manche dieser Techniken sind ergänzend und andere wiederum für denselben Einsatzzweck gedacht und stellen damit eine Konkurrenz dar. Ein Vergleich kann für eine Einordnung spannend sein und dir beim Einstieg helfen, wenn du bereits Erfahrungen mit einer der folgenden Techniken hast.
Web Components
Web Components sind der Standard für eine ganze Reihe von Techniken sein16. Jede dieser Techniken kann man in Kombination mit den anderen oder für sich allein verwenden.
Custom Elements17 erlauben die Definition von eigenen HTML-Tags inklusive lokalem CSS und JavaScript. Du kannst also sowohl Aussehen als auch Verhalten für ein solches neues HTML-Tag definieren.
Shadow DOM
Über das sogenannte Shadow DOM18, in dem sich die Komponente darstellt, wird die Lokalität der Komponente realisiert.
HTML Templates19 lassen dich HTML in die Seite einbinden, ohne dass es unmittelbar auf der Seite dargestellt wird. Dies kann nützlich sein, um das Template später durch ein Skript mit Werten zu versehen und im Browser-DOM darzustellen. Obwohl diese Erweiterung als Teil von Web Components begonnen hat, wird sie nun als Teil der HTML-Spezifikation weiterentwickelt.
Die Programmierung von Web Components erfolgt imperativ und mit Listenern. Die Bibliothek Lit Elements20 stellt für Web Components ein deklaratives Programmiermodell zur Verfügung, das vom Konzept an React erinnert.
Verwendung von Web Components in React-Komponenten
Web Components können wie jedes andere HTML-Element in einer React-Komponente genutzt werden. Diese Möglichkeit war eine bewusste Entscheidung der React-Entwickler. Hier sperrt man sich also nicht gegen Web Components, auch wenn es bei der Integration einige technische Schwierigkeiten gibt21.
Andere wiederum sehen in React eher eine Konkurrenz zu Web Components, sind aber mit React nicht zufrieden, weil es kein Standard ist. Laut der Aussage eines React-Kern-Entwicklers wird sich React nicht an Web Components annähern, allerdings auch nicht den Gebrauch zusammen mit React ausschließen, sondern ihn so weit wie möglich unterstützen22.
Der Hype »vor React«
Angular kommt in zwei unterschiedlichen Versionen daher, die mehr oder weniger unterschiedlich und inkompatibel sind. Angular 123 (»AngularJS«) gibt es schon sehr lange und man kann es ohne Wenn und Aber den »Hype vor React« nennen. Angular in der Version 2 hat mit einer ganzen Reihe von Konzepten aus Angular 1 gebrochen. Die Versionen ab Angular 2 werden deswegen auch »Angular« genannt (im Gegensatz zu »AngularJS«, was sich auf Version 1 bezieht).
Sowohl AngularJS als auch Angular sind jeweils ein komplettes Framework, inklusive Router und klaren Vorstellungen von einer Architektur und der Art und Weise, wie getestet wird. So gibt es neben Komponenten zum Beispiel ein Modulkonzept, Services und Dependency Injection. Angular ist mit TypeScript entwickelt und auch Angular-Anwendungen werden darin geschrieben.
Vue24 ist ebenfalls ein komponentenbasiertes JavaScript-Framework zur Entwicklung von Single-Page-Anwendungen. Im Gegensatz zu React kommen hier viele Bausteine mit, etwa ein Router und eine offiziell unterstützte Redux-Version für das Zustandsmanagement.
Vue verwendet genau wie Angular eine Template-Sprache, hat aber eine schlankere API und macht weniger Vorgaben, wie die Anwendung strukturiert sein soll. Das Framework wurde 2014 veröffentlicht, wird von einer Open-Source-Community entwickelt und hat sehr schnell eine große Verbreitung gefunden. Die Version 3 von Vue wird genau wie Angular in TypeScript entwickelt.
Native Anwendungen mit React Native
React Native bietet eine Möglichkeit, mit React native Komponenten nicht nur für das Web, sondern auch für andere Systeme (unter anderem Android und iOS) zu entwickeln. Dabei wird eine andere Version des virtuellen DOM verwendet, die eine React-Komponente nicht für den DOM aufbereitet, sondern auf native Komponenten des Betriebssystems abbildet. Als JavaScript-Engine kommt sowohl bei Android als auch bei iOS Webkits JavaScript-Engine JavaScriptCore25 zum Einsatz.
Die in diesem Buch behandelten Themen sind komplex und umfangreich, zudem befinden sie sich in vielen Teilen im Fluss. Alle Themen auf dem neuesten Stand in einem Buch zu behandeln, ist daher nicht möglich. Stattdessen nehmen wir dich als Leser an die Hand und führen dich an die zentralen Themen der React-Welt heran. Für einige Details und weiterführende Informationen verweisen wir mithilfe von Links auf die aktuellsten Quellen im Internet.
Die Teile des Buchs
Das Buch gliedert sich in drei Teile.
Hands-on-Abschnitte
Jedes Kapitel in Teil II und III beginnt mit einem Hands-on-Abschnitt. In diesem werden anhand eines praktischen Beispiels die wichtigsten Konzepte des Kapitels erläutert. In den weiteren Teilen des Kapitels wird dann je nach Schwerpunkt des Kapitels die Anwendung weiterentwickelt und/oder auf weitere Details eingegangen.
Auch wenn du die in den Hands-on-Teilen beschriebenen Schritte nicht selber nachprogrammierst, kannst du damit einen praktischen Überblick über das vorgestellte Thema bekommen. Daher haben wir in den Teilen auch relativ viel Code abgedruckt, damit du zum Nachvollziehen nicht vor dem Computer sitzen musst.
Die Kapitel des Buchs bauen aufeinander auf. Ab Kapitel 4 verwenden wir durchgehend unsere Beispielanwendung, um die Konzepte von React zu demonstrieren. Insbesondere im dritten Teil sind die vorgestellten Technologien und Bibliotheken teilweise so komplex, dass wir sie am Anfang des Kapitels im Hands-on-Teil an einem kleinen, separaten Beispiel zeigen. Im Laufe des Kapitels beschreiben wir dann in Ausschnitten, wie sich die jeweilige Technologie auf unsere Anwendung auswirkt.
ES5-Kenntnisse notwendig
Wir verwenden in diesem Buch konsequent die JavaScript-Versionen ECMAScript 2015 und neuer (ES.Next). Es genügt aber, wenn du mit der vorangegangenen Version ES5 vertraut bist. Die wichtigsten von uns verwendeten Neuerungen der Sprache haben wir im Anhang zusammengestellt, sodass du dort bei Bedarf nachschlagen kannst.
HTML und DOM
Neben ES5 solltest du außerdem HTML und das Document Object Model (DOM) kennen.
npm
Wenn du die Beispiele ausprobieren möchtest, muss auf deinem Rechner der Node Package Manager npm installiert sein. Mit npm werden wir die Module (Frameworks und Bibliotheken) für unsere Anwendung installieren und die Anwendung auch starten. Achtung: Die Beispiele sind mit npm in der Version 6.9.x getestet!
Node.js
Für den serverseitigen Beispielcode verwenden wir Node.js. Wenn du diese Teile ausprobieren möchtest, brauchst du eine Node.js-Installation auf deinem Rechner. (Wir haben mit Version 10.16.x getestet.)
Die zweite Auflage wurde komplett überarbeitet und stellt jetzt die Hooks-API in den Vordergrund. Wir zeigen die wichtigsten React Hooks sowie die Hooks-API von React Router, Redux und GraphQL.
Neu hinzugekommen sind außerdem Beschreibungen diverser React-APIs, wie Suspense, Caching oder Code-Splitting, Tests mit der React Testing Library und das Tool Create React App. Außerdem betrachten wir die Entwicklung von React-Anwendungen mit TypeScript. Als Grundlage dafür gibt es im Anhang eine Einführung in die Sprache TypeScript.
Wir haben zu diesem Buch eine Website eingerichtet, über die du unter anderem zu unserem GitHub-Repository mit dem Beispielcode findest. Auf der Seite werden wir aber auch Korrekturen und Ergänzungen zum Buch und zu den Beispielen veröffentlichen, insbesondere auch zu Neuerungen in React. Die Adresse der Seite lautet:
https://reactbuch.de
Anregungen, Kommentare und Fragen nehmen wir jederzeit gerne entgegen. Du kannst uns erreichen unter der E-Mail-Adresse:
reactbuch@nilshartmann.net
oder über Twitter:
Nils Hartmann @nilshartmann
Oliver Zeigermann @DJCordhose
Alternativ kannst du uns auch im GitHub-Repository der Beispielanwendung gerne einen Issue einstellen (https://github.com/react-buch/vote-example-v2/issues).
Bei der Erstellung dieses Buchs haben uns eine ganze Reihe von Menschen geholfen, denen wir ganz herzlich danken wollen!
Unser Dank gilt dabei auch denjenigen, die das Buch schon vor der Fertigstellung gelesen und kommentiert haben und die auch für diese zweite Auflage sehr gutes Feedback gegeben haben.
Darüber hinaus möchten wir uns ganz herzlich beim Team vom dpunkt.verlag und allen an der Produktion Beteiligten bedanken, die uns nach Kräften geholfen und mit Rat und Tat zur Seite gestanden haben.
Bevor wir in die Details von React gehen, möchten wir dir in diesem Kapitel die wichtigsten Features von React im Schnelldurchgang an einem sehr einfachen Beispiel zeigen. Das Beispiel kannst du auf der Plattform CodeSandbox, die Online-Editoren für JavaScript anbietet, nachvollziehen, ohne dass du dafür etwas bei dir lokal auf deinem Computer installieren musst. (CodeSandbox selbst ist übrigens auch mit React gebaut.)
Um das Beispiel zu entwickeln, kannst du in CodeSandbox ein neues React-Projekt anlegen. Dazu öffnest du https://codesandbox.io/, klickst auf »Create Sandbox« und wählst dann unter »Popular Templates« »React« aus. Daraufhin wird ein Projekt angelegt, in dem die Abhängigkeiten auf die React-npm-Module bereits hinzugefügt sind und einige weitere Dateien angelegt sind.
Je nach Einstellung findest du auf der linken Seite einen Explorer mit allen Dateien des Projekts, in der Mitte einen Editor (der sich wie VS Code verwenden lässt!) und rechts die Darstellung deiner Anwendung in einem simulierten Browser. Sobald du den Code deiner Anwendung veränderst, wird die Anwendung übersetzt (z.B. JSX nach ES5) und die Darstellung im simulierten Browser automatisch aktualisiert.
Für diesen Schnelleinstieg wollen wir eine ganz einfache Hello-World-Anwendung bauen, die nur aus einer einzigen Komponente besteht. Komponenten sind das zentrale Element in React und wie wir später noch sehen werden, sind Anwendungen in React nichts weiter als eine Menge von Komponenten.
Die Komponente unserer Anwendung, Greeter, besteht aus einem Eingabefeld, in dem ein Gruß eingegeben werden kann. Der eingegebene Gruß darf eine bestimmte Länge nicht überschreiten. Die Anzahl der verbleibenden Zeichen steht unterhalb des Eingabefeldes. Außerdem gibt es einen Knopf, der den aktuellen Gruß ausgibt. Aktiv ist der Knopf allerdings nur, wenn der Gruß »gültig« ist, das bedeutet, er enthält mindestens ein Zeichen und die Länge ist kleiner oder gleich der erlaubten Maximallänge.
Beispiel: die Greeter-Komponente
Der erste Schritt unserer Anwendung sieht wie folgt aus, du kannst diesen Code so, wie er da steht, in die index.js-Datei deiner Sandbox einsetzen:
import React from "react";
export default function Greeter(props) {
const [greeting, setGreeting] = React.useState("");
function handleGreetClick() {
alert(`Hello, ${greeting}`);
}
const charsRemaining = props.maxLength - greeting.length;
const greetingInvalid = greeting.length === 0
|| charsRemaining < 0;
return (
<div>
Greeting:
<input value={greeting}
onChange={e => setGreeting(e.target.value)} />
<span>{charsRemaining}</span>
<button disabled={greetingInvalid}
onClick={handleGreetClick}>Greet
</button>
</div>
);
}
Sehen wir uns den Code der Komponente Schritt für Schritt an. Eine Komponente in React ist eine JavaScript-Funktion. In dieser Komponentenfunktion ist alles enthalten, was die Komponente benötigt, um sich darstellen zu können: sowohl die Logik als auch die UI.
Beschreibung der UI mit JSX
Die UI, die unsere Komponente darstellen soll, findest du im return-Statement der Komponente. Dort haben wir mit einer HTML-artigen Syntax die Elemente beschrieben, die zur Laufzeit im Browser dargestellt werden sollen. Dieser HTML-artige Code, JSX genannt, wird zur Build-Zeit von einem Compiler (Babel oder TypeScript) in gültiges JavaScript übersetzt. Für uns hat dieser Ansatz den Vorteil, dass wir keine Template-Sprache lernen und verwenden müssen (auch wenn dieses Vorgehen am Anfang sicherlich gewöhnungsbedürftig und vielleicht sogar abschreckend sein mag).
Variablen verwenden
Innerhalb des JSX-Codes können wir auf JavaScript-Variablen und -Funktionen zugreifen. Im Button, der den Gruß anzeigen soll, geben wir damit an, ob der Button aktiv oder inaktiv sein soll. Außerdem geben wir eine Callback-Funktion an, die ausgeführt werden soll, sobald auf den Button geklickt wird. Diese Eigenschaften eines Elementes werden in React Properties genannt. Sowohl disabled als auch onClick sind somit Properties des Button-Elements, genauso wie value und onChange Properties des input-Felds sind.
Properties
maxLengthpropsprops.maxLength