Successfully reported this slideshow.
Your SlideShare is downloading. ×

react-de.pdf

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
REACT Docs - Deutsch
REACT Docs - Deutsch
1
Table of contents
Accessibility 5
Add react to a website 17
Addons animation 22
Addons create fragment 30
Addons perf 32
A...
Fragments 134
Getting started 137
Handling events 141
Hello world 144
Higher order components 146
Hooks custom 155
Hooks e...
Advertisement
Advertisement
Advertisement
Advertisement
Advertisement
Advertisement
Advertisement
Advertisement
Advertisement
Advertisement
Upcoming SlideShare
vitepress-en.pdf
vitepress-en.pdf
Loading in …3
×

Check these out next

1 of 454 Ad
Advertisement

More Related Content

Recently uploaded (20)

Advertisement

react-de.pdf

  1. 1. REACT Docs - Deutsch REACT Docs - Deutsch 1
  2. 2. Table of contents Accessibility 5 Add react to a website 17 Addons animation 22 Addons create fragment 30 Addons perf 32 Addons pure render mixin 35 Addons shallow compare 36 Addons shallow renderer 37 Addons test utils 39 Addons two way binding helpers 46 Addons update 49 Addons 52 Cdn links 54 Code splitting 55 Codebase overview 61 Components and props 65 Composition vs inheritance 70 Conditional rendering 74 Context 79 Create a new react app 86 Cross origin errors 89 Design principles 91 Error boundaries 98 Error decoder 103 Faq ajax 104 Faq build 107 Faq functions 108 Faq internals 115 Faq state 116 Faq structure 119 Faq styling 121 Faq versioning 122 Forms 125 Forwarding refs 131 react 2
  3. 3. Fragments 134 Getting started 137 Handling events 141 Hello world 144 Higher order components 146 Hooks custom 155 Hooks effect 161 Hooks faq 172 Hooks intro 193 Hooks overview 198 Hooks reference 204 Hooks rules 221 Hooks state 224 How to contribute 231 Implementation notes 237 Integrating with other libraries 255 Introducing jsx 257 Jsx in depth 261 Legacy context 270 Legacy event pooling 275 Lifting state up 276 Lists and keys 284 Optimizing performance 289 Portals 299 React without es6 302 React without jsx 306 Reconciliation 307 Reference dom elements 312 Reference events 317 Reference glossary 325 Reference javascript environment requirements 330 Reference profiler 331 Reference pure render mixin 334 Reference react component 336 Reference react dom client 352 Reference react dom server 354 REACT Docs - Deutsch 3
  4. 4. Reference react dom 359 Reference react 364 Reference test renderer 374 Refs and the dom 380 Release channels 387 Render props 390 Rendering elements 397 State and lifecycle 400 Static type checking 409 Strict mode 417 Testing environments 424 Testing recipes 426 Testing 437 Thinking in react 439 Typechecking with proptypes 445 Uncontrolled components 450 Web components 452 react 4
  5. 5. Barrierefreiheit Warum Barrierefreiheit? Barrierefreiheit im Web (Auch bekannt unter dem Begriff a11y) beschreibt Design und Umset- zung von Websites welche ausnahmlos von Jedem genutzt werden können. Barriefreiheit ist not- wendig um Assistenzprogrammen das Interpretieren von Websites zu ermöglichen. React unterstützt das Erstellen von barrierefreien Webseiten in vollem Ausmaß, unter anderem durch die Nutzung von Standard-HTML-Technologien. Standards und Anleitungen WCAG Die Web Content Accessibility Guidelines enthalten Anleitungen um barrierefreie Webseiten zu erstellen. Die folgenden WCAG-Checklisten geben einen kurzen Überblick: WCAG checklist von Wuhcag WCAG checklist von WebAIM Checklist von dem A11Y Project WAI-ARIA Das Web Accessibility Initiative - Accessible Rich Internet Applications Dokument zeigt Techniken für das Entwickeln vollkommen barrierefreier JavaScript Widgets. Es gilt, dass alle aria-* HTML-Attribute in JSX komplett unterstützt werden. Während die meis- ten DOM-Eigenschaften und Attribute in React in camelCase umgesetzt werden, sollten diese At- tribute hyphen-cased (auch bekannt als kebab-case, lisp-case, usw.) sein, so wie man es auch bei normalem HTML tun würde: <input type="text" aria-label={labelText} aria-required="true" onChange={onchangeHandler} value={inputValue} name="name" /> Barrierefreiheit 5
  6. 6. Semantisches HTML Semantisches HTML ist das Fundament der Barrierefreiheit einer Webanwendung. Das Nutzen der verschiedenen HTML-Elemente, welche die Bedeutung einer Information betonen bringt dir oft- mals Barrierefreiheit ohne extra Aufwand. MDN HTML elements reference Manchmal wird die Bedeutung verschiedener HTML Elemente verfälscht indem ein <div> Ele- ment um das JSX hinzugefügt wird um den React-Code zum laufen zu bringen, besonders häufig beim Arbeiten mit Listen ( <ol> , <ul> und <dl> ) und der HTML <table> . Hier sollten besser React Fragments genutzt werden um mehrere Elemente in einer Gruppe zusammenzufassen. Zum Beispiel, Es ist auch möglich mehrere Fragmente in einem Array mit Hilfe der map -Funktion zusammenzu- fassen, genauso wie du es bei anderen Element auch tun würdest: Solltest du keine Props für einen Fragment-Tag brauchen kannst du die folgende short syntax nutzen, sofern dein JS-Tooling diese unterstützt: import React, { Fragment } from 'react'; function ListItem({ item }) { return ( <Fragment> <dt>{item.term}</dt> <dd>{item.description}</dd> </Fragment> ); } function Glossary(props) { return ( <dl> {props.items.map(item => ( <ListItem item={item} key={item.id} /> ))} </dl> ); } function Glossary(props) { return ( <dl> {props.items.map(item => ( // Fragments should also have a `key` prop when mapping collections <Fragment key={item.id}> <dt>{item.term}</dt> <dd>{item.description}</dd> </Fragment> ))} </dl> ); } react 6
  7. 7. Weitere Infos findest in der Dokumentation über Fragments. Barrierefreie Formulare Kennzeichnung Jedes HTML Formularelement, wie zum Beispiel <input> und <textarea> , muss barrierefrei gekennzeichnet werden. Es müssen beschreibende Kennzeichnungen, welche für Screenreader relevant sind, vorhanden sein. In folgenden Quellen kannst du nachlesen wie dies am besten umzusetzen ist: Das W3C zeigt wie Elemente zu kennzeichnen sind WebAIM zeigt wie Elemente zu kennzeichnen sind Die Paciello Gruppe erklärt barrierefreie Namen Auch wenn diese HTML-Standards direkt in React genutzt werden können, solltest du darauf ach- ten dass das for -Attribut in JSX htmlFor heißt. Den Nutzer über Fehler informieren Fehlersituation müssen von allen Nutzern gleich verstanden werden. Die folgenden Links zeigen uns wie man Fehlermeldungen auch für Screenreader interpretierbar gestaltet: Das W3C demonstriert Fehlermeldungen WebAIM nimmt sich der Formularvalidierung an Fokuskontrolle Stelle sicher dass deine Webanwendung vollständig per Tastatur bedienbar ist: WebAIM spricht über Barrierefreiheit mit Tastatur Tastatur-Fokus und Fokussierung Der Tastatur-Fokus zeigt auf das aktuell ausgewählte DOM-Element welches Eingaben der Tasta- tur annimmt. Man sieht dies überall anhand der Fokussierung (Außenlinie), genau wie diese im folgenden Bild: function ListItem({ item }) { return ( <> <dt>{item.term}</dt> <dd>{item.description}</dd> </> ); } <label htmlFor="namedInput">Name:</label> <input id="namedInput" type="text" name="name"/> Barrierefreiheit 7
  8. 8. Verwende nur dann CSS zum Entfernen dieser Linie, zum Beispiel indem du outline: 0 setzt, wenn du sie durch eine andere Implementierung der Fokus-Markierung ersetzt. Mechanismen um direkt zum wichtigsten Inhalt zu springen Stelle einen Mechanismus zur Verfügung welcher die Navigationselemente deiner Webanwendung überspringt. Dies beschleunigt die Navigation mit der Tastatur. Skiplinks, oder auch Skip-Navigation-Links sind versteckte Navigations-Links die nur dann sicht- bar werden wenn Tastaturnutzer mit der Seite interagieren. Diese sind sehr einfach mit internen Seitenankern und etwas Styling umzusetzen: WebAIM - Skip Navigation Links Also use landmark elements and roles, such as <main> and <aside> , to demarcate page regi- ons as assistive technology allow the user to quickly navigate to these sections. Nutze Außerdem semantische Elemente und Rollen, wie zum Beispiel <main> und <aside> um verschiedene Be- reiche deiner Seite voneinander abzugrenzen, da es entprechende Assitenztechnologien so dem User erlauben sich schnell zwischen diesen Elementen zurecht zu finden. Mehr über den Einsatz dieser Elemente zur Verbesserung der Barrierefreiheit erfährst du hier: Accessible Landmarks Den Fokus programmatisch verwalten Unsere React-Anwendungen verändern das HTML-DOM kontinuierlich zur Laufzeit, dies führt dazu, dass der Tastatur-Fokus gelegentlich verloren geht oder auf ein unvorhersehbares Element gesetzt wird. Um diesem Umstand zuvor zu kommen, müssen wir hier programmatisch nachhel- fen. Zum Beispiel indem wir den Tastatur-Fokus wieder auf den Button setzen, welcher ein Modal geöffnet hat, nachdem dieses geschlossen wurde. MDN Web Docs takes a look at this and describes how we can build keyboard-navigable Java- Script widgets. Die MDN Web Docs beschreiben wie wir Tastaturgesteurte JavaScript Widgets rea- lisieren können. Um mit React einen Fokus zu setzen, können wir Refs auf DOM-Elementen nutzen. Hierzu erstellen wir zuerst eine Elementreferenz im JSX einer Component-Klasse: class CustomTextInput extends React.Component { constructor(props) { super(props); // Create a ref to store the textInput DOM element this.textInput = React.createRef(); } render() { react 8
  9. 9. Danach können wir den Fokus beliebig verändern, falls nötig: Gelegentlich ist es nötig, dass eine Eltern-Komponente den Fokus auf ein Element einer Kind- Komponente setzen muss. Dies lässt sich mit dem Bereitstellen von DOM-Referenzen einer El- tern-Komponente mit einer speziellen Eigenschaft, welche die Referenz der Eltern-Komponente zur Kind-Komponente weitergibt, umsetzen. Falls du eine HOC nutzt empfiehlt es sich die Referenz zur umschlossenen Komponente weiterzu- geben indem du die forwardRef React-Funktion nutzt. Sollte eine Drittanbieter HOC diese Tech- nik nicht implementiert haben kannst du das oben verwendete Pattern als einen Fallback nutzen. Ein gutes Fokus-Beispielt ist das react-aria-modal. Dies ist ein relativ rares Beispiel eines voll- ständig barrierefreiem Modal-Fenster. Hier wird der initiale Fokus auf den Abbrechen Button ge- setzt (Um den User davon abzuhalten versehentlich die Success-Action zu aktivieren) und der Fo- kus kann nicht aus dem Modal-Fenster springen. Nachdem das Modal geschlossen wird wird der Fokus wieder zurück auf das Element gesetzt welches das Modal-Fenster getriggered hat. // Use the `ref` callback to store a reference to the text input DOM // element in an instance field (for example, this.textInput). return ( <input type="text" ref={this.textInput} /> ); } } focus() { // Explicitly focus the text input using the raw DOM API // Note: we're accessing "current" to get the DOM node this.textInput.current.focus(); } function CustomTextInput(props) { return ( <div> <input ref={props.inputRef} /> </div> ); } class Parent extends React.Component { constructor(props) { super(props); this.inputElement = React.createRef(); } render() { return ( <CustomTextInput inputRef={this.inputElement} /> ); } } // Now you can set focus when required. this.inputElement.current.focus(); Barrierefreiheit 9
  10. 10. Hinweis: Es handelt sich hier um ein wichtiges Feature, welches jedoch in einem vernünftigen Rah- men genutzt werden sollte. Nutze dieses Feature, um den Tastatur-Fokus anzupassen, falls der Flow der App gestört sein sollte und versuche nicht, die Tastaturnutzung des Users zu antizipieren. Maus- und Pointerevents Stelle sicher, dass alle Funktionalitäten, welche durch die Maus oder den Zeiger hervorgerufen werden, auch via Tastatur gesteuert werden können. Sich komplett von einem Zeigergerät ab- hängig zu machen, führt dazu, dass deine App für viele Tastaturnutzer unbrauchbar wird. Um dies zu verdeutlichen, schauen wir uns ein Anwendungsbeispiel an, bei dem die Barrierefrei- heit durch Click-Events gestört ist. Hier siehst du das "outside-click"-Pattern, in welchem der User eine geöffnete Popup-Nachricht schließen kann, indem er außerhalb des Elements klickt. Typischerweise wird Dies durch ein Klick-Event auf dem window -Objekt implementiert welches die Popover-Nachricht schließt: class OuterClickExample extends React.Component { constructor(props) { super(props); this.state = { isOpen: false }; this.toggleContainer = React.createRef(); this.onClickHandler = this.onClickHandler.bind(this); this.onClickOutsideHandler = this.onClickOutsideHandler.bind(this); } componentDidMount() { window.addEventListener('click', this.onClickOutsideHandler); } componentWillUnmount() { window.removeEventListener('click', this.onClickOutsideHandler); } onClickHandler() { react 10
  11. 11. Dies würde natürlich mit Zeigergeräten, wie zB. der Maus, super funktionieren, mit der Tastatur alleine führt dies jedoch zu mangelhafter Funktionalität wenn du das nächste Element per Tab er- reichst. In diesem Fall das click -Event nie auf dem window -Objekt aufgerufen. Dies kann zu obskuren Fehlern führen, welche es manchen Usern unmöglich macht deine App zu nutzen. Die gleiche Funktionalität kann durch geeignete Eventhandler, wie zum Beispiel onBLur und onFocus , erreicht werden: this.setState(currentState => ({ isOpen: !currentState.isOpen })); } onClickOutsideHandler(event) { if (this.state.isOpen && !this.toggleContainer.current.contains(event.target)) { this.setState({ isOpen: false }); } } render() { return ( <div ref={this.toggleContainer}> <button onClick={this.onClickHandler}>Select an option</button> {this.state.isOpen && ( <ul> <li>Option 1</li> <li>Option 2</li> <li>Option 3</li> </ul> )} </div> ); } } class BlurExample extends React.Component { constructor(props) { super(props); this.state = { isOpen: false }; this.timeOutId = null; this.onClickHandler = this.onClickHandler.bind(this); this.onBlurHandler = this.onBlurHandler.bind(this); this.onFocusHandler = this.onFocusHandler.bind(this); Barrierefreiheit 11
  12. 12. Der obige Code gewährleistet die Funktionalität sowohl für Zeigergeräte als auch für Tastaturen. Beachte auch die aria-* Attribute zur Unterstützung von Screenreadern. Der Einfachheit halber wurden hier keine Pfeiltasten-Events implementiert um mit dem Popover zu interagieren. } onClickHandler() { this.setState(currentState => ({ isOpen: !currentState.isOpen })); } // We close the popover on the next tick by using setTimeout. // This is necessary because we need to first check if // another child of the element has received focus as // the blur event fires prior to the new focus event. onBlurHandler() { this.timeOutId = setTimeout(() => { this.setState({ isOpen: false }); }); } // If a child receives focus, do not close the popover. onFocusHandler() { clearTimeout(this.timeOutId); } render() { // React assists us by bubbling the blur and // focus events to the parent. return ( <div onBlur={this.onBlurHandler} onFocus={this.onFocusHandler}> <button onClick={this.onClickHandler} aria-haspopup="true" aria-expanded={this.state.isOpen}> Select an option </button> {this.state.isOpen && ( <ul> <li>Option 1</li> <li>Option 2</li> <li>Option 3</li> </ul> )} </div> ); } } react 12
  13. 13. Dies hier ist nur ein Beispiel für viele Fälle bei denen die Funktionalität nicht gewährleistet ist wenn du dich nur auf Zeiger-Events verlässt. Ein beständiges Testen mit der Tastutur zeigt dir auch die Schwachstellen, welche mit angemessenen Eventhandlern beseitigt werden können. Kompliziertere Widgets Kompliziertere Handlungen sollten nicht mit weniger Barrierefreiheit einhergehen. Während Bar- rierefreiheit am einfachen damit umgesetzt werden kann sich so gut wie möglich an den HTML- Standard zu halten, können auch die kompliziertesten Widgets barrierefrei implementiert werden. Here we require knowledge of ARIA Roles as well as ARIA States and Properties. Wir setzen hier Grundkentinsse in den ARIA Rollen sowie den ARIA Zuständen und Eigenschaften hervor. Jede Art von Widget hat ein spezielles Designpattern und sollte für User und deren Useragents wie folgt funktionieren: WAI-ARIA Konventionen - Designppatterns und Widgets Heydon Pickering - ARIA Beispiele Inclusive Components Andere wichtige Punkte Einstellung der Sprache Gib immer die in den Texten deiner Seite verwendete Sprache an, da Screen-Reader-Software diese Angabe nutzt um die richtigen Spracheinstellungen auszuwählen. WebAIM - Document Language Der Titel des Dokuments Verwende den Dokumenten <title> um den aktuellen Inhalt der Seite korrekt zu beschreiben, da dies sicherstellt, dass der Benutzer über den aktuellen Seitenkontext informiert ist. WCAG - Den Bedarf eines Dokumenten-Titels verstehen In React können wir Diesen mit dem React Document Title Component realisieren. Barrierefreiheit 13
  14. 14. Farbkontraste Stelle sicher, dass die Texte deiner Webseite ausreichende Farbkontraste aufweisen, um auch von Nutzern mit Sehschwäche problemlos lesbar zu sein: WCAG - Den Bedarf für Farbkontrast verstehen Alles über den Farbkontrast und warum man ihn überdenken sollte A11yProject - Was ist Farbkontrast Es kann sehr anstrengend sein die richtigen Farbkombinationen für alle Anwendungsfälle deiner Webseite manuell zu erstellen, anstatt dessen kannst du eine vollständig barrierefreie Farbpalette mit Colorable berechnen. Sowohl die unten erwähnten aXe als auch die WAVE-Werkzeuge beinhalten Farbkontrast-Tests welche dich über fehlerhafte Kontraste informieren. Wenn du deine Kontraste noch genauer testen willst kannst du die folgenden Werkzeuge verwenden: WebAIM - Farbkontrast Checker Die Paciello Gruppe - Farbkontrast Analyzer Entwicklungs- und Testingtools Es gibt eine Reihe von Werkzeugen um dich bei der Erstellung barrierefreier Webanwendungen zu unterstützen. Die Tastatur Die mit Abstand einfachste und auch eine der wichtigsten Prüfungen ist es, zu testen, ob deine gesamte Webseite allein mit der Tastatur erreichbar und nutzbar ist. Teste dies wie folgt: 1. Deaktiviere deine Maus. 2. Nutze Tab und Shift+Tab um zu navigieren. 3. Nutze Enter um Elemente zu aktivieren. 4. Falls nötig, nutze die Pfeiltasten zur Interaktion mit manchen Elementen, wie z.B. Menüs und Dropdowns. Hilfsmittel für Entwickler Einige Punkte der Barrierefreiheit können direkt in unserem JSX-Code getestet werden. Oftmals gibt es bereits Intellisense-Tests für ARIA-Roles, States und Properties in JSX-fähigen IDE's. Au- ßerdem steht uns das folgende Werkzeug zur Verfügung: eslint-plugin-jsx-a11y Das eslint-plugin-jsx-a11y ESLint-Plugin stellt AST-Linting-Feedback bezogen auf Probleme mit der Barrierefreiheit in deinem JSX zur Verfügung. Viele IDE's machen es dir möglich diese Funk- tionalität direkt in die Code-Analyse oder die Coding-Oberfläche zu integrieren. react 14
  15. 15. Create React App verfügt über ein Plugin welches einen Teil dieser Regeln aktiviert hat. Solltest du noch mehr Regeln zur Barrierefreiheit nutzen wollen, kannst im Stammverzeichnis deines Pro- jekts eine .eslintrc -Datei mit folgendem Inhalt anlegen: Barrierefreiheit im Browser testen Es gibt eine Reihe von Werkzeugen, die Barrierefreiheitsprüfungen auf deinen Webseiten im Browser durchführen können. Bitte nutze Diese nur in Verbindung mit den bereits genannten Werkzeugen, da diese Tests nur die technische Barrierefreiheit in deinem HTML kontrollieren können. aXe, aXe-core und react-axe Deque Systems bietet aXe-core für automatisierte End-to-End-Tests deiner Anwendung an. Die- ses Modul enthält auch Einbindungen für Selenium. The Accessibility Engine, oder aXe, ist eine Browser-Erweiterung basierend auf aXe-core , die ei- nen Inspektor für Barrierefreiheit bereitstellt. Außerdem kannst du das @axe-core/react Modul nutzen, um die Ergebnisse dieser Barrierefrei- heitskontrollen während der Entwicklung direkt in der Konsole auszugeben. WebAIM WAVE Das Web Accessibility Evaluation Tool ist eine weitere Browser-Erweiterung. Barrierefreiheitsprüfer und der Barrierefreiheitsbaum Der Barrierefreiheitsbaum ist eine Teilmenge des DOM-Baums, welche barrierefreie Objekte für jedes DOM-Element, das für unterstützende Technologie wie z. B. Screen-Readern sichtbar sein sollte, enthält. In einigen Browsern ist es einfach möglich die Informationen zur Barrierefreiheit für jedes Ele- ment des Barrierefreiheitsbaums zu überprüfen: Den Barrierefreiheitsprüfer in Firefox nutzen Den Barrierefreiheitsprüfer in Chrome nutzen Den Barrierefreiheitsprüfer in OS X Safari nutzen Screen-Reader Das Testen mit einem Screen-Reader sollte bei deinen Tests zur Barrierefreiheit nicht fehlen. Beachte dass es auf die Browser / Screen-Reader Kombination ankommt. Es wird empfohlen, dass du deine Anwendung in dem Browser testest, der am besten zu deinem gewählten Screen- Reader passt. { "extends": ["react-app", "plugin:jsx-a11y/recommended"], "plugins": ["jsx-a11y"] } Barrierefreiheit 15
  16. 16. Häufig genutzte Screen-Reader NVDA im Firefox NonVisual Desktop Access, auch NVDA, ist ein häufig genutzter Screen-Reader für Windows. Nutze die folgenden Hinweise, um zu erfahren wie NVDA am besten zu nutzen ist: WebAIM - NVDA zur Auswertung der Web-Barrierefreiheit Deque - NVDA Tastenkombinationen VoiceOver im Safari VoiceOver ist ein in Apple-Geräte integrierter Screen-Reader. Nutze die folgenden Hinweise, um zu erfahren wie man VoiceOver aktiviert: WebAIM - VoiceOver zur Auswertung der Web-Barrierefreiheit Deque - VoiceOver für OS X Tastenkombinationen Deque - VoiceOver für iOS Kombinationen JAWS im Internet Explorer Job Access With Speech, auch JAWS, ist ein häufig genutzter Screen-Reader für Windows. Nutze die folgenden Hinweise, um zu erfahren wie JAWS am besten zu nutzen ist: WebAIM - JAWS zur Auswertung der Web-Barrierefreiheit Deque - JAWS Tastenkombinationen Weitere Screen-Reader ChromeVox im Google Chrome ChromeVox ist ein in Chromebooks integrierter Screen-Reader und ist außerdem als eine Erweite- rung für Chrome verfügbar. Nutze die folgenden Hinweise, um zu erfahren wie ChromeVox am besten zu nutzen ist: Google Chromebook Hilfe - Nutzung des integrierten Screen-Readers ChromeVox Referenz der klassischen Tastenkombinationen react 16
  17. 17. React einer Webseite hinzufügen Verwende so wenig oder so viel React wie du möchtest. React wurde von Beginn an für eine schrittweise Benutzung konzipiert und du kannst so wenig oder so viel React benutzen, wie du möchtest. Vielleicht möchtest du zu einer existierenden Seite nur an wenigen Stellen ein paar kleine "Spritzer von Interaktivität" hinzufügen. React Komponen- ten sind perfekt dafür geeignet. Die Mehrheit der Webseiten sind und brauchen keine SPAs zu sein. Probiere React in einem klei- nen Teil deiner Webseite mit ein paar Zeilen Code und ohne Build-Werkzeuge aus. Dann kannst du die Verwendung entweder schrittweise erweitern oder auf ein paar dynamische Wid- gets beschränken. Füge React in einer Minute hinzu Optional: Benutze React mit JSX (Kein Bundler benötigt!) Füge React in einer Minute hinzu Wir wollen in diesem Abschnitt zeigen, wie man einer existierenden HTML Seite eine React Kom- ponente hinzufügen kann. Um zu üben kannst du deine eigene Webseite benutzen oder eine leere HTML Seite erstellen. Es sind keine komplizierten Werkzeuge oder Installationen nötig -- Um diesem Abschnitt zu folgen, brauchst du nur eine Internetverbindung und eine Minute deiner Zeit. Optional: Komplettes Beispiel herunterladen (2KB gezippt) Schritt 1: Einen DOM Container dem HTML hinzufügen Öffne als erstes die HTML Seite, die du editieren möchtest. Füge ein leeres <div> Tag hinzu, um die Stelle zu markieren, an der du mit React etwas anzeigen möchtest. Zum Beispiel: Wir haben diesem div ein eindeutiges id HTML Attribut gegeben. Das erlaubt es uns es später mit JavaScript wiederzufinden und darin eine React Komponente anzuzeigen. Tipp <!-- ... existierendes HTML ... --> <div id="like_button_container"></div> <!-- ... existierendes HTML ... --> React einer Webseite hinzufügen 17
  18. 18. Du kannst einen "Container" <div> wie das oben überall im <body> Tag setzen. Du kannst so viele unabhängige DOM Container in einer Seite haben wie du brauchst. Norma- lerweise sind sie leer -- Falls die DOM Container Inhalt besitzen, wird React diesen überschreiben. Schritt 2: Füge die Script Tags hinzu Als nächstes fügen wir direkt vor dem schließenden </body> Tag drei <script> Tags der HTML Seite hinzu: Die ersten zwei Tags laden React. Der dritte läd deinen Komponenten Code. Schritt 3: Erstelle eine React Komponente Erstelle eine Datei mit dem Namen like_button.js und speichere sie neben deiner HTML Seite. Öffne den Starter Code und füge Sie in die Datei ein, die du erstellt hast. Tipp Dieser Code definiert eine React Komponente mit dem Namen LikeButton . Mach dir keine Sorgen, falls du das noch nicht verstehst -- Wir werden die Bausteine von React später in unserem hands-on Tutorial und dem Leitfaden der Hauptkonzepte behandeln. Jetzt wollen wir sie erstmal im Browser angezeigt bekommen! Nach dem Starter Code, füge zwei Zeilen am Ende von like_button.js an: Diese drei Codezeilen finden den <div> Container aus dem ersten Schritt und zeigen dann unse- re React Komponente mit dem "Like" Button darin an. <!-- ... anderes HTML ... --> <!-- React laden. --> <!-- Hinweis: Wenn du die Seite bereitstellen willst, ersetze "development.js" mit "product <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></scr <!-- Unsere React Komponente laden. --> <script src="like_button.js"></script> </body> // ... Der Start Code, den du gerade eingefügt hast ... const domContainer = document.querySelector('#like_button_container'); const root = ReactDOM.createRoot(domContainer); root.render(e(LikeButton)); react 18
  19. 19. Das ist alles! Es gibt keinen vierten Schritt. Du hast gerade deine erste React Komponente zu deiner Webseite hinzugefügt. Sieh dir die nächsten Abschnitte an, um mehr Tipps zu erhalten, wie du React integrieren kannst. Öffne den ganzen Beispiel Source Code Das komplette Beispiel herunterladen (2KB gezippt) Tipp: Verwende Komponeten wieder Häufig wirst du React Komponenten an verschiedenen Stellen einer HTML Seite anzeigen wollen. Hier ist ein Beispiel, welches den "Like" Button dreimal anzeigt und einige Daten hinzufügt. Öffne den ganzen Beispiel Source Code Das komplette Beispiel herunterladen (2KB gezippt) Hinweis Diese Herangehensweise ist besonders sinnvoll, wenn mit React gebaute Teile der Seite voneinander isoliert sind. In React Code selbst ist es einfacher stattdessen Komponenten Komposition zu verwenden. Tipp: Minifiziere JavaScript für die Produktionsumgebung Bevor du deine Webseite für die Produktionsumgebung deployst, denke daran, dass unminifizier- tes JavaScript die Seite für deine User signifankt verlangsamen kann. Falls du bereits die Anwendungsscripts minifiziert hast, ist deine Seite fertig für die Produkti- onsumgebung, sobald du sichergestellt hast, dass das bereitgestellte HTML die Versionen von React lädt, die auf production.min.js enden: Falls du deine Skripte nicht minifizierst, wird hier wird ein möglicher Weg zur Minifizierung gezeigt. Optional: Benutze React mit JSX In den Beispielen haben wir nur Funktionalitäten verwendet, die von Browsern nativ unterstützt werden. Deswegen haben wir einen Methodenaufruf in JavaScript benutzt, um React zu sagen, was angezeigt werden soll: <script src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></sc <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossori React einer Webseite hinzufügen 19
  20. 20. React bietet allerdings auch die Option an, stattdessen JSX zu benutzen. Diese zwei Codebeispiele sind äquivalent. Obwohl JSX komplett optional ist, finden es viele Leute beim Schreiben von UI Code hilfreich -- sowohl mit React als auch mit anderen Bibliotheken. Du kannst JSX mit diesem Online Konverter ausprobieren. Schnell JSX ausprobieren Du kannst JSX in deinem Projekt am schnellsten ausprobieren, indem du diesen <script> Tag deiner Seite hinzufügst: Jetzt kannst JSX in jedem <script> Tag verwenden, indem du diesem ein type="text/babel" Attribut hinzufügst. Hier kannst du eine Besipiel HTML Datei mit JSX herunterladen und mit ihr experimentieren. Um zu lernen und einfache Demos zu bauen ist dieser Ansatz ausreichend. Allerdings macht er deine Webseite langsam und ist nicht für die Produktionsumgebung geeignet. Wenn du be- reit bist weiter zu machen, entferne den neuen <script> Tag und das type="text/babel" , das du eben hinzugefügt hast. Im nächsten Abschnitt wirst du stattdessen einen JSX Präprozes- sor aufsetzen, der alle deine <script> Tags automatisch konvertiert. Füge JSX einem Projekt hinzu Einem Projekt JSX hinzuzufügen benötigt keine komplizierten Werkzeuge wie einen Bundler oder einen Entwicklungsserver. JSX einbinden ist ähnlich wie einen CSS Präprozessor einzubin- den. Als einzige Voraussetzung musst du Node.js auf deinem Computer installiert haben. Navigiere im Terminal zu deinem Projektordner und führe diese zwei Befehle aus: 1. Schritt 1: Führe npm init -y aus (falls es fehlgeschlägt, gibt es hier Hilfe) 2. Schritt 2: Führe npm install babel-cli@6 babel-preset-react-app@3 aus const e = React.createElement; // Zeige einen "Like" <button> an return e( 'button', { onClick: () => this.setState({ liked: true }) }, 'Like' ); // Zeige einen "Like" <button> an return ( <button onClick={() => this.setState({ liked: true })}> Like </button> ); <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> react 20
  21. 21. Tipp Wir benutzen hier npm nur, um den JSX Präprozessor zu installieren; Du wirst es für nichts anderes brauchen. Sowohl React als auch der Anwendungscode können ohne Ände- rung weiter als <script> Tags eingebunden werden. Herzlichen Glückwunsch! Du hast gerade ein JSX Setup eingerichtet, das für die Produktions- umgebung bereit ist. Starte den JSX Präprozessor Erzeuge einen Ordner mit dem Namen src und führe folgenden Befehl aus: Hinweis npx ist kein Schreibfehler -- es ist ein Werkzeug um Pakete direkt auszuführen (package runner tool), welches seit npm 5.2 mitgeliefert wird Falls du eine Fehlermeldung mit dem Text "You have mistakenly installed the babel packa- ge" siehst, hast du vielleicht den vorherigen Schritt übersprungen. Führe diesen im gleichen Ordner aus und probier es nochmal. Du brauchst nicht darauf zu warten, dass der Befehl fertig ausgeführt wird -- er startet einen au- tomatisierten Watcher für JSX. Wenn du jetzt eine Datei unter src/like_button.js mit diesem JSX Starter Code erstellst, wird der Watcher eine präprozessierte like_button.js mit einfachem JavaScript Code erstellen, der im Browser ausgeführt werden kann. Wenn Sie die Quelldatei mit JSX bearbeiten, wird das Bauen der Datei automatisch erneut ausgeführt. Zusätzlich kannst du durch diesen Ansatz moderne JavaScript Syntax Funktionalitäten wie Klas- sen verwenden, ohne dass dein Code in alten Browsern nicht funktionieren würde. Falls du merkst, dass du im Umgang mit Build-Werkzeugen sicher wirst und du von ihnen mehr machen lassen willst, beschreibt der nächste Abschnitt einige der beliebtesten und zugänglichs- ten Ansammlungen von diesen. Falls aber nicht -- Script Tags sind genauso ok! npx babel --watch src --out-dir . --presets react-app/prod React einer Webseite hinzufügen 21
  22. 22. Animation Add-Ons Note: ReactTransitionGroup and ReactCSSTransitionGroup have been moved to the react- transition-group package that is maintained by the community. Its 1.x branch is com- pletely API-compatible with the existing addons. Please file bugs and feature requests in the new repository. The ReactTransitionGroup add-on component is a low-level API for animation, and React‐ CSSTransitionGroup is an add-on component for easily implementing basic CSS animations and transitions. High-level API: ReactCSSTransitionGroup ReactCSSTransitionGroup is a high-level API based on ReactTransitionGroup and is an easy way to perform CSS transitions and animations when a React component enters or leaves the DOM. It's inspired by the excellent ng-animate library. Importing import ReactCSSTransitionGroup from 'react-transition-group'; // ES6 var ReactCSSTransitionGroup = require('react-transition-group'); // ES5 with npm class TodoList extends React.Component { constructor(props) { super(props); this.state = {items: ['hello', 'world', 'click', 'me']}; this.handleAdd = this.handleAdd.bind(this); } handleAdd() { const newItems = this.state.items.concat([ prompt('Enter some text') ]); this.setState({items: newItems}); } handleRemove(i) { let newItems = this.state.items.slice(); newItems.splice(i, 1); this.setState({items: newItems}); } render() { const items = this.state.items.map((item, i) => ( <div key={i} onClick={() => this.handleRemove(i)}> {item} </div> )); react 22
  23. 23. Note: You must provide the key attribute for all children of ReactCSSTransitionGroup , even when only rendering a single item. This is how React will determine which children have en- tered, left, or stayed. In this component, when a new item is added to ReactCSSTransitionGroup it will get the ex‐ ample-enter CSS class and the example-enter-active CSS class added in the next tick. This is a convention based on the transitionName prop. You can use these classes to trigger a CSS animation or transition. For example, try adding this CSS and adding a new list item: You'll notice that animation durations need to be specified in both the CSS and the render me- thod; this tells React when to remove the animation classes from the element and -- if it's leaving -- when to remove the element from the DOM. return ( <div> <button onClick={this.handleAdd}>Add Item</button> <ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300}> {items} </ReactCSSTransitionGroup> </div> ); } } .example-enter { opacity: 0.01; } .example-enter.example-enter-active { opacity: 1; transition: opacity 500ms ease-in; } .example-leave { opacity: 1; } .example-leave.example-leave-active { opacity: 0.01; transition: opacity 300ms ease-in; } Animation Add-Ons 23
  24. 24. Animate Initial Mounting ReactCSSTransitionGroup provides the optional prop transitionAppear , to add an extra transition phase at the initial mount of the component. There is generally no transition phase at the initial mount as the default value of transitionAppear is false . The following is an ex- ample which passes the prop transitionAppear with the value true . During the initial mount ReactCSSTransitionGroup will get the example-appear CSS class and the example-appear-active CSS class added in the next tick. At the initial mount, all children of the ReactCSSTransitionGroup will appear but not enter . However, all children later added to an existing ReactCSSTransitionGroup will enter but not appear . Note: The prop transitionAppear was added to ReactCSSTransitionGroup in version 0.13 . To maintain backwards compatibility, the default value is set to false . However, the default values of transitionEnter and transitionLeave are true so you must specify transitionEnterTimeout and transitionLeaveTimeout by default. If you don't need either enter or leave animations, pass transitionEnter={false} or transi‐ tionLeave={false} . render() { return ( <ReactCSSTransitionGroup transitionName="example" transitionAppear={true} transitionAppearTimeout={500} transitionEnter={false} transitionLeave={false}> <h1>Fading at Initial Mount</h1> </ReactCSSTransitionGroup> ); } .example-appear { opacity: 0.01; } .example-appear.example-appear-active { opacity: 1; transition: opacity .5s ease-in; } react 24
  25. 25. Custom Classes It is also possible to use custom class names for each of the steps in your transitions. Instead of passing a string into transitionName you can pass an object containing either the enter and leave class names, or an object containing the enter , enter-active , leave-active , and leave class names. If only the enter and leave classes are provided, the enter-active and leave- active classes will be determined by appending '-active' to the end of the class name. Here are two examples using custom classes: Animation Group Must Be Mounted To Work In order for it to apply transitions to its children, the ReactCSSTransitionGroup must already be mounted in the DOM or the prop transitionAppear must be set to true . The example below would not work, because the ReactCSSTransitionGroup is being mounted along with the new item, instead of the new item being mounted within it. Compare this to the Getting Started section above to see the difference. // ... <ReactCSSTransitionGroup transitionName={ { enter: 'enter', enterActive: 'enterActive', leave: 'leave', leaveActive: 'leaveActive', appear: 'appear', appearActive: 'appearActive' } }> {item} </ReactCSSTransitionGroup> <ReactCSSTransitionGroup transitionName={ { enter: 'enter', leave: 'leave', appear: 'appear' } }> {item2} </ReactCSSTransitionGroup> // ... render() { const items = this.state.items.map((item, i) => ( <div key={item} onClick={() => this.handleRemove(i)}> <ReactCSSTransitionGroup transitionName="example"> {item} </ReactCSSTransitionGroup> </div> )); return ( <div> <button onClick={this.handleAdd}>Add Item</button> {items} Animation Add-Ons 25
  26. 26. Animating One or Zero Items In the example above, we rendered a list of items into ReactCSSTransitionGroup . However, the children of ReactCSSTransitionGroup can also be one or zero items. This makes it possible to animate a single element entering or leaving. Similarly, you can animate a new element repla- cing the current element. For example, we can implement a simple image carousel like this: Disabling Animations You can disable animating enter or leave animations if you want. For example, sometimes you may want an enter animation and no leave animation, but ReactCSSTransitionGroup waits for an animation to complete before removing your DOM node. You can add transition‐ Enter={false} or transitionLeave={false} props to ReactCSSTransitionGroup to disable these animations. Note: When using ReactCSSTransitionGroup , there's no way for your components to be noti- fied when a transition has ended or to perform any more complex logic around animation. If you want more fine-grained control, you can use the lower-level ReactTransitionGroup API which provides the hooks you need to do custom transitions. Low-level API: ReactTransitionGroup Importing </div> ); } import ReactCSSTransitionGroup from 'react-transition-group'; function ImageCarousel(props) { return ( <div> <ReactCSSTransitionGroup transitionName="carousel" transitionEnterTimeout={300} transitionLeaveTimeout={300}> <img src={props.imageSrc} key={props.imageSrc} /> </ReactCSSTransitionGroup> </div> ); } import ReactTransitionGroup from 'react-addons-transition-group' // ES6 var ReactTransitionGroup = require('react-addons-transition-group') // ES5 with npm react 26
  27. 27. ReactTransitionGroup is the basis for animations. When children are declaratively added or re- moved from it (as in the example above), special lifecycle methods are called on them. componentWillAppear() componentDidAppear() componentWillEnter() componentDidEnter() componentWillLeave() componentDidLeave() Rendering a Different Component ReactTransitionGroup renders as a span by default. You can change this behavior by provi- ding a component prop. For example, here's how you would render a <ul> : Any additional, user-defined, properties will become properties of the rendered component. For example, here's how you would render a <ul> with CSS class: Every DOM component that React can render is available for use. However, component does not need to be a DOM component. It can be any React component you want; even ones you've writ- ten yourself! Just write component={List} and your component will receive this.prop‐ s.children . Rendering a Single Child People often use ReactTransitionGroup to animate mounting and unmounting of a single child such as a collapsible panel. Normally ReactTransitionGroup wraps all its children in a span (or a custom component as described above). This is because any React component has to re- turn a single root element, and ReactTransitionGroup is no exception to this rule. However if you only need to render a single child inside ReactTransitionGroup , you can com- pletely avoid wrapping it in a <span> or any other DOM component. To do this, create a custom component that renders the first child passed to it directly: Now you can specify FirstChild as the component prop in <ReactTransitionGroup> props and avoid any wrappers in the result DOM: <ReactTransitionGroup component="ul"> {/* ... */} </ReactTransitionGroup> <ReactTransitionGroup component="ul" className="animated-list"> {/* ... */} </ReactTransitionGroup> function FirstChild(props) { const childrenArray = React.Children.toArray(props.children); return childrenArray[0] || null; } Animation Add-Ons 27
  28. 28. This only works when you are animating a single child in and out, such as a collapsible panel. This approach wouldn't work when animating multiple children or replacing the single child with another child, such as an image carousel. For an image carousel, while the current image is ani- mating out, another image will animate in, so <ReactTransitionGroup> needs to give them a common DOM parent. You can't avoid the wrapper for multiple children, but you can customize the wrapper with the component prop as described above. Reference componentWillAppear() {#componentwillappear} This is called at the same time as componentDidMount() for components that are initially moun- ted in a TransitionGroup . It will block other animations from occurring until callback is cal- led. It is only called on the initial render of a TransitionGroup . componentDidAppear() {#componentdidappear} This is called after the callback function that was passed to componentWillAppear is called. componentWillEnter() {#componentwillenter} This is called at the same time as componentDidMount() for components added to an existing TransitionGroup . It will block other animations from occurring until callback is called. It will not be called on the initial render of a TransitionGroup . componentDidEnter() {#componentdidenter} This is called after the callback function that was passed to componentWillEnter() is called. componentWillLeave() {#componentwillleave} <ReactTransitionGroup component={FirstChild}> {someCondition ? <MyComponent /> : null} </ReactTransitionGroup> componentWillAppear(callback) componentDidAppear() componentWillEnter(callback) componentDidEnter() componentWillLeave(callback) react 28
  29. 29. This is called when the child has been removed from the ReactTransitionGroup . Though the child has been removed, ReactTransitionGroup will keep it in the DOM until callback is called. componentDidLeave() {#componentdidleave} This is called when the willLeave callback is called (at the same time as componentWillUn‐ mount() ). componentDidLeave() Animation Add-Ons 29
  30. 30. Keyed Fragments Note: React.addons entry point is deprecated as of React v15.5. We now have first class sup- port for fragments which you can read about here. Importing Overview In most cases, you can use the key prop to specify keys on the elements you're returning from render . However, this breaks down in one situation: if you have two sets of children that you need to reorder, there's no way to put a key on each set without adding a wrapper element. That is, if you have a component such as: The children will unmount and remount as you change the swapped prop because there aren't any keys marked on the two sets of children. To solve this problem, you can use the createFragment add-on to give keys to the sets of children. Array<ReactNode> createFragment(object children) {#arrayreactnode-createfrag- mentobject-children} Instead of creating arrays, we write: import createFragment from 'react-addons-create-fragment'; // ES6 var createFragment = require('react-addons-create-fragment'); // ES5 with npm function Swapper(props) { let children; if (props.swapped) { children = [props.rightChildren, props.leftChildren]; } else { children = [props.leftChildren, props.rightChildren]; } return <div>{children}</div>; } import createFragment from 'react-addons-create-fragment'; function Swapper(props) { let children; if (props.swapped) { children = createFragment({ right: props.rightChildren, react 30
  31. 31. The keys of the passed object (that is, left and right ) are used as keys for the entire set of children, and the order of the object's keys is used to determine the order of the rendered child- ren. With this change, the two sets of children will be properly reordered in the DOM without unmounting. The return value of createFragment should be treated as an opaque object; you can use the React.Children helpers to loop through a fragment but should not access it directly. Note also that we're relying on the JavaScript engine preserving object enumeration order here, which is not guaranteed by the spec but is implemented by all major browsers and VMs for objects with non-numeric keys. left: props.leftChildren }); } else { children = createFragment({ left: props.leftChildren, right: props.rightChildren }); } return <div>{children}</div>; } Keyed Fragments 31
  32. 32. Performance Tools Note: As of React 16, react-addons-perf is not supported. Please use your browser's profiling tools to get insight into which components re-render. Importing Overview React is usually quite fast out of the box. However, in situations where you need to squeeze every ounce of performance out of your app, it provides a shouldComponentUpdate() method where you can add optimization hints to React's diff algorithm. In addition to giving you an overview of your app's overall performance, Perf is a profiling tool that tells you exactly where you need to put these methods. See these articles for an introduction to React performance tooling: "How to Benchmark React Components" "Performance Engineering with React" "A Deep Dive into React Perf Debugging" Development vs. Production Builds If you're benchmarking or seeing performance problems in your React apps, make sure you're testing with the minified production build. The development build includes extra warnings that are helpful when building your apps, but it is slower due to the extra bookkeeping it does. However, the perf tools described on this page only work when using the development build of React. Therefore, the profiler only serves to indicate the relatively expensive parts of your app. Using Perf The Perf object can be used with React in development mode only. You should not include this bundle when building your app for production. Getting Measurements start() stop() import Perf from 'react-addons-perf'; // ES6 var Perf = require('react-addons-perf'); // ES5 with npm react 32
  33. 33. getLastMeasurements() Printing Results The following methods use the measurements returned by Perf.getLastMeasurements() to pretty-print the result. printInclusive() printExclusive() printWasted() printOperations() printDOM() Reference start() {#start} stop() {#stop} Start/stop the measurement. The React operations in-between are recorded for analyses below. Operations that took an insignificant amount of time are ignored. After stopping, you will need Perf.getLastMeasurements() to get the measurements. getLastMeasurements() {#getlastmeasurements} Get the opaque data structure describing measurements from the last start-stop session. You can save it and pass it to the other print methods in Perf to analyze past measurements. Note Don't rely on the exact format of the return value because it may change in minor releases. We will update the documentation if the return value format becomes a supported part of the public API. printInclusive() {#printinclusive} Perf.start() // ... Perf.stop() Perf.getLastMeasurements() Perf.printInclusive(measurements) Performance Tools 33
  34. 34. Prints the overall time taken. When no arguments are passed, printInclusive defaults to all the measurements from the last recording. This prints a nicely formatted table in the console, like so: printExclusive() {#printexclusive} "Exclusive" times don't include the times taken to mount the components: processing props, cal- ling componentWillMount and componentDidMount , etc. printWasted() {#printwasted} The most useful part of the profiler. "Wasted" time is spent on components that didn't actually render anything, e.g. the render stay- ed the same, so the DOM wasn't touched. printOperations() {#printoperations} Prints the underlying DOM manipulations, e.g. "set innerHTML" and "remove". printDOM() {#printdom} This method has been renamed to printOperations() . Currently printDOM() still exists as an alias but it prints a deprecation warning and will eventually be removed. Perf.printExclusive(measurements) Perf.printWasted(measurements) Perf.printOperations(measurements) Perf.printDOM(measurements) react 34
  35. 35. PureRenderMixin Note: PureRenderMixin is a legacy add-on. Use React.PureComponent instead. Importing Overview If your React component's render function renders the same result given the same props and sta- te, you can use this mixin for a performance boost in some cases. Example: Under the hood, the mixin implements shouldComponentUpdate, in which it compares the cur- rent props and state with the next ones and returns false if the equalities pass. Note: This only shallowly compares the objects. If these contain complex data structures, it may produce false-negatives for deeper differences. Only mix into components which have sim- ple props and state, or use forceUpdate() when you know deep data structures have changed. Or, consider using immutable objects to facilitate fast comparisons of nested data. Furthermore, shouldComponentUpdate skips updates for the whole component subtree. Make sure all the children components are also "pure". import PureRenderMixin from 'react-addons-pure-render-mixin'; // ES6 var PureRenderMixin = require('react-addons-pure-render-mixin'); // ES5 with npm const createReactClass = require('create-react-class'); createReactClass({ mixins: [PureRenderMixin], render: function() { return <div className={this.props.className}>foo</div>; } }); PureRenderMixin 35
  36. 36. Shallow Compare Note: shallowCompare is a legacy add-on. Use React.memo or React.PureComponent instead. Importing Overview Before React.PureComponent was introduced, shallowCompare was commonly used to achieve the same functionality as PureRenderMixin while using ES6 classes with React. If your React component's render function is "pure" (in other words, it renders the same result given the same props and state), you can use this helper function for a performance boost in some cases. Example: shallowCompare performs a shallow equality check on the current props and nextProps ob- jects as well as the current state and nextState objects. It does this by iterating on the keys of the objects being compared and returning true when the values of a key in each object are not strictly equal. shallowCompare returns true if the shallow comparison for props or state fails and therefore the component should update. shallowCompare returns false if the shallow comparison for props and state both pass and therefore the component does not need to update. import shallowCompare from 'react-addons-shallow-compare'; // ES6 var shallowCompare = require('react-addons-shallow-compare'); // ES5 with npm export class SampleComponent extends React.Component { shouldComponentUpdate(nextProps, nextState) { return shallowCompare(this, nextProps, nextState); } render() { return <div className={this.props.className}>foo</div>; } } react 36
  37. 37. Shallow Renderer Import Übersicht Beim Schreiben von unit tests kann flaches Rendering (engl. shallow rendering) hilfreich sein. Flaches Rendering ermöglicht es, eine Komponente "einen Level tief" zu rendern, und vergleicht den zurückgegebenen Wert der Render Methode, ohne sich über das Verhalten der Kind-Kompo- nenten, welche nicht instanziiert oder gerendert werden, Sorgen zu machen. Ein DOM wird hier- bei nicht verlangt. Wenn du zum Beispiel folgende Komponente hast: So können wir sie testen: Flaches Rendering hat derzeit die Einschränkung, dass refs nicht unterstützt werden. Hinweis: Wir empfehlen auch, sich die Shallow Rendering API von Enzyme anzusehen. Sie stellt eine angenehmere übergeordnete API mit den gleichen Funktionalitäten bereit. import ShallowRenderer from 'react-test-renderer/shallow'; // ES6 var ShallowRenderer = require('react-test-renderer/shallow'); // ES5 mit npm function MyComponent() { return ( <div> <span className="heading">Titel</span> <Subcomponent foo="bar" /> </div> ); } import ShallowRenderer from 'react-test-renderer/shallow'; // in deinem Test: const renderer = new ShallowRenderer(); renderer.render(<MyComponent />); const result = renderer.getRenderOutput(); expect(result.type).toBe('div'); expect(result.props.children).toEqual([ <span className="heading">Titel</span>, <Subcomponent foo="bar" /> ]); Shallow Renderer 37
  38. 38. Referenz shallowRenderer.render() {#shallowrendererrender} Du kannst dir den shallowRenderer als den "Ort" vorstellen an dem die zu testende Komponente gerendert wird, und du daraus die Ausgabe der Komponente entnehmen kannst. shallowRenderer.render() ist ähnlich wie root.render() , nur dass es kein DOM benötigt und nur einen Level tief rendert. Das bedeutet, dass du Komponenten abgegrenzt testen kannst, unabhängig davon wie die Kind-Komponenten implementiert sind. shallowRenderer.getRenderOutput() {#shallowrenderergetrenderoutput} Nachdem shallowRenderer.render() aufgerufen wurde, kannst du dir mit shallowRenderer‐ .getRenderOutput() die flach gerenderte Ausgabe zurückgeben lassen. Dann kann man anfangen, die Ausgabe zu testen. react 38
  39. 39. Test-Utilities Import Übersicht ReactTestUtils bieten eine einfache Möglichkeit, React-Komponenten in einem Test-Framework deiner Wahl zu testen. Bei Facebook benutzen wir Jest für schmerzfreie Javascript-Tests. Du kannst das React-Tutorial auf Jest's Webseite besuchen, um Jest zu lernen. Hinweis: Wir empfehlen die Verwendung der React Testing Library, die konzipiert wurde, um das Schreiben von Tests zu ermöglichen, in denen Komponenten auf die gleiche Weise verwen- det werden wie von Endnutzern. Für React-Versionen <= 16 macht es die Enzyme Bibliothek einfach, die Ausgabe deiner React-Komponenten zu prüfen, zu manipulieren und zu durchlaufen. act() mockComponent() isElement() isElementOfType() isDOMComponent() isCompositeComponent() isCompositeComponentWithType() findAllInRenderedTree() scryRenderedDOMComponentsWithClass() findRenderedDOMComponentWithClass() scryRenderedDOMComponentsWithTag() findRenderedDOMComponentWithTag() scryRenderedComponentsWithType() findRenderedComponentWithType() renderIntoDocument() Simulate import ReactTestUtils from 'react-dom/test-utils'; // ES6 var ReactTestUtils = require('react-dom/test-utils'); // ES5 mit npm Test-Utilities 39
  40. 40. Referenz act() {#act} Um eine Komponente für Assertionen vorzubereiten, setze den Code, der sie rendert und aktuali- siert, in einen act() -Aufruf. Damit läuft der Test so ähnlich ab, wie React auch im Browser funktioniert. Hinweis Falls du react-test-renderer verwendest, kannst du dessen act -Export verwenden, der sich gleich verhält. Stelle dir als Beispiel vor, du hast diese Counter -Komponente: So können wir sie testen: class Counter extends React.Component { constructor(props) { super(props); this.state = {count: 0}; this.handleClick = this.handleClick.bind(this); } componentDidMount() { document.title = `Du hast ${this.state.count} Mal geklickt`; } componentDidUpdate() { document.title = `Du hast ${this.state.count} Mal geklickt`; } handleClick() { this.setState(state => ({ count: state.count + 1, })); } render() { return ( <div> <p>Du hast {this.state.count} Mal geklickt</p> <button onClick={this.handleClick}> Klick mich </button> </div> ); } } import React from 'react'; import ReactDOM from 'react-dom/client'; import { act } from 'react-dom/test-utils'; import Counter from './Counter'; let container; beforeEach(() => { react 40
  41. 41. Vergiss nicht, dass das Abschicken von DOM-Events nur funktioniert, wenn der DOM-Container zum document hinzugefügt wurde. Du kannst React Testing Library zur Hilfe nehmen, um Boilerplate-Code zu reduzieren. Das recipes Dokument enthält mehr Details dazu, wie sich act() verhält, mit Beispiele und Anwendungsgebieten. mockComponent() {#mockcomponent} Übergebe dieser Methode ein gemocktes Komponenten-Modul, um es mit nützlichen Methoden zu erweitern, mit denen es als Dummy-React-Komponente verwendet werden kann. Anstatt wie üb- lich zu rendern, wird die Komponente zu einem einfachen <div> (oder zu einem anderen Tag , falls mockTagName angegeben wurde), das die ihr übergegebenen Children-Elemente enthält. Hinweis: mockComponent() ist eine veraltete API. Wir empfehlen, stattdessen jest.mock() zu verwenden. container = document.createElement('div'); document.body.appendChild(container); }); afterEach(() => { document.body.removeChild(container); container = null; }); it('kann einen Counter rendern und updaten', () => { // Erstes Rendern und componentDidMount testen act(() => { ReactDOM.createRoot(container).render(<Counter />); }); const button = container.querySelector('button'); const label = container.querySelector('p'); expect(label.textContent).toBe('Du hast 0 Mal geklickt'); expect(document.title).toBe('Du hast 0 Mal geklickt'); // Zweites Rendern und componentDidUpdate testen act(() => { button.dispatchEvent(new MouseEvent('click', {bubbles: true})); }); expect(label.textContent).toBe('Du hast 1 Mal geklickt'); expect(document.title).toBe('Du hast 1 Mal geklickt'); }); mockComponent( componentClass, [mockTagName] ) Test-Utilities 41
  42. 42. isElement() {#iselement} Gibt true zurück, falls element ein React-Element ist. isElementOfType() {#iselementoftype} Gibt true zurück, falls element ein React-Element vom Typ React componentClass ist. isDOMComponent() {#isdomcomponent} Gibt true zurück, falls instance eine DOM-Komponente (z. B. ein <div> oder <span> ) ist. isCompositeComponent() {#iscompositecomponent} Gibt true zurück, falls instance eine benutzerdefinierte Komponente, z. B. eine Klasse oder Funktion, ist. isCompositeComponentWithType() {#iscompositecomponentwithtype} Gibt true zurück, falls instance eine Komponente vom Typ React componentClass ist. findAllInRenderedTree() {#findallinrenderedtree} isElement(element) isElementOfType( element, componentClass ) isDOMComponent(instance) isCompositeComponent(instance) isCompositeComponentWithType( instance, componentClass ) findAllInRenderedTree( tree, test ) react 42
  43. 43. Durchläuft alle Komponenten in tree und sammelt alle Komponenten, bei denen test(compo‐ nent) true ist. Das ist für sich allein genommen nicht besonders nützlich, wird aber als Primiti- ve für andere Test-Utilities verwendet. scryRenderedDOMComponentsWithClass() {#scryrendereddomcomponentswithclass} Findet alle DOM-Elemente von Komponenten im gerenderten Baum, bei denen der Klassennamen der Komponenten mit className übereinstimmt. findRenderedDOMComponentWithClass() {#findrendereddomcomponentwithclass} Verhält sich wie scryRenderedDOMComponentsWithClass() , erwartet aber genau ein Resultat und gibt dieses zurück. Gibt einen Fehler aus, falls es mehr oder weniger als eine Übereinstim- mung gibt. scryRenderedDOMComponentsWithTag() {#scryrendereddomcomponentswithtag} Findet alle DOM-Elemente von Komponenten im gerenderten Baum, bei denen der Tagname der Komponenten mit tagName übereinstimmt. findRenderedDOMComponentWithTag() {#findrendereddomcomponentwithtag} scryRenderedDOMComponentsWithClass( tree, className ) findRenderedDOMComponentWithClass( tree, className ) scryRenderedDOMComponentsWithTag( tree, tagName ) findRenderedDOMComponentWithTag( tree, tagName ) Test-Utilities 43
  44. 44. Verhält sich wie scryRenderedDOMComponentsWithTag() , erwartet aber genau ein Resultat und gibt dieses zurück. Gibt einen Fehler aus, falls es mehr oder weniger als eine Übereinstimmung gibt. scryRenderedComponentsWithType() {#scryrenderedcomponentswithtype} Findet alle Instanzen von Komponenten, deren Typ mit componentClass übereinstimmt. findRenderedComponentWithType() {#findrenderedcomponentwithtype} Verhält sich wie scryRenderedComponentsWithType() , erwartet aber genau ein Resultat und gibt dieses zurück. Gibt einen Fehler aus, falls es mehr oder weniger als eine Übereinstimmung gibt. renderIntoDocument() {#renderintodocument} Rendert ein React-Element in einen separaten DOM-Knoten im Dokument. Diese Funktion be- nötigt ein DOM. Effektiv ist sie äquivalent zu: Hinweis: window , window.document und window.document.createElement müssen global ver- fügbar sein, bevor du React importierst. Ansonsten denkt React, dass es nicht auf das DOM zugreifen kann, und Methoden wie setState werden nicht funktionieren. scryRenderedComponentsWithType( tree, componentClass ) findRenderedComponentWithType( tree, componentClass ) renderIntoDocument(element) const domContainer = document.createElement('div'); ReactDOM.createRoot(domContainer).render(element); react 44
  45. 45. Andere Utilities Simulate {#simulate} Simuliere das Abschicken eines Events auf einen DOM-Knoten mit optionalen eventData - Eventdaten. Simulate hat eine Methode für jedes Event, das React versteht. Ein Element anklicken Den Wert eines Input-Feldes verändern und dann ENTER drücken Hinweis Du musst jede Event-Eigenschaft angeben, die du in deiner Komponente verwendest (z. B. keyCode, which, etc.), da React keine davon für dich erstellt. Simulate.{eventName}( element, [eventData] ) // <button ref={(node) => this.button = node}>...</button> const node = this.button; ReactTestUtils.Simulate.click(node); // <input ref={(node) => this.textInput = node} /> const node = this.textInput; node.value = 'Giraffe'; ReactTestUtils.Simulate.change(node); ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13}); Test-Utilities 45
  46. 46. Two-way Binding Helpers Note: LinkedStateMixin is deprecated as of React v15. The recommendation is to explicitly set the value and change handler, instead of using LinkedStateMixin . Importing Overview LinkedStateMixin is an easy way to express two-way binding with React. In React, data flows one way: from owner to child. We think that this makes your app's code ea- sier to understand. You can think of it as "one-way data binding." However, there are lots of applications that require you to read some data and flow it back into your program. For example, when developing forms, you'll often want to update some React state when you receive user input. Or perhaps you want to perform layout in JavaScript and re- act to changes in some DOM element size. In React, you would implement this by listening to a "change" event, read from your data source (usually the DOM) and call setState() on one of your components. "Closing the data flow loop" explicitly leads to more understandable and easier-to-maintain programs. See our forms docu- mentation for more information. Two-way binding -- implicitly enforcing that some value in the DOM is always consistent with some React state -- is concise and supports a wide variety of applications. We've provided LinkedStateMixin : syntactic sugar for setting up the common data flow loop pattern described above, or "linking" some data source to React state . Note: LinkedStateMixin is just a thin wrapper and convention around the onChange / setSta‐ te() pattern. It doesn't fundamentally change how data flows in your React application. LinkedStateMixin: Before and After Here's a simple form example without using LinkedStateMixin : import LinkedStateMixin from 'react-addons-linked-state-mixin'; // ES6 var LinkedStateMixin = require('react-addons-linked-state-mixin'); // ES5 with npm react 46
  47. 47. This works really well and it's very clear how data is flowing, however, with a lot of form fields it could get a bit verbose. Let's use LinkedStateMixin to save us some typing: LinkedStateMixin adds a method to your React component called linkState() . linkState() returns a valueLink object which contains the current value of the React state and a callback to change it. valueLink objects can be passed up and down the tree as props, so it's easy (and explicit) to set up two-way binding between a component deep in the hierarchy and state that lives higher in the hierarchy. Note that checkboxes have a special behavior regarding their value attribute, which is the value that will be sent on form submit if the checkbox is checked (defaults to on ). The value attribu- te is not updated when the checkbox is checked or unchecked. For checkboxes, you should use checkedLink instead of valueLink : Under the Hood There are two sides to LinkedStateMixin : the place where you create the valueLink instance and the place where you use it. To prove how simple LinkedStateMixin is, let's rewrite each side separately to be more explicit. var createReactClass = require('create-react-class'); var NoLink = createReactClass({ getInitialState: function() { return {message: 'Hello!'}; }, handleChange: function(event) { this.setState({message: event.target.value}); }, render: function() { var message = this.state.message; return <input type="text" value={message} onChange={this.handleChange} />; } }); var createReactClass = require('create-react-class'); var WithLink = createReactClass({ mixins: [LinkedStateMixin], getInitialState: function() { return {message: 'Hello!'}; }, render: function() { return <input type="text" valueLink={this.linkState('message')} />; } }); <input type="checkbox" checkedLink={this.linkState('booleanValue')} /> Two-way Binding Helpers 47
  48. 48. valueLink Without LinkedStateMixin As you can see, valueLink objects are very simple objects that just have a value and re‐ questChange prop. And LinkedStateMixin is similarly simple: it just populates those fields with a value from this.state and a callback that calls this.setState() . LinkedStateMixin Without valueLink The valueLink prop is also quite simple. It simply handles the onChange event and calls this.props.valueLink.requestChange() and also uses this.props.valueLink.value ins- tead of this.props.value . That's it! var createReactClass = require('create-react-class'); var WithoutMixin = createReactClass({ getInitialState: function() { return {message: 'Hello!'}; }, handleChange: function(newValue) { this.setState({message: newValue}); }, render: function() { var valueLink = { value: this.state.message, requestChange: this.handleChange }; return <input type="text" valueLink={valueLink} />; } }); var LinkedStateMixin = require('react-addons-linked-state-mixin'); var createReactClass = require('create-react-class'); var WithoutLink = createReactClass({ mixins: [LinkedStateMixin], getInitialState: function() { return {message: 'Hello!'}; }, render: function() { var valueLink = this.linkState('message'); var handleChange = function(e) { valueLink.requestChange(e.target.value); }; return <input type="text" value={valueLink.value} onChange={handleChange} />; } }); react 48
  49. 49. Immutability Helpers Note: update is a legacy add-on. Use immutability-helper instead. Importing Overview React lets you use whatever style of data management you want, including mutation. However, if you can use immutable data in performance-critical parts of your application it's easy to imple- ment a fast shouldComponentUpdate() method to significantly speed up your app. Dealing with immutable data in JavaScript is more difficult than in languages designed for it, like Clojure. However, we've provided a simple immutability helper, update() , that makes dealing with this type of data much easier, without fundamentally changing how your data is represented. You can also take a look at Facebook's Immutable-js and the Advanced Performance section for more detail on Immutable-js. The Main Idea If you mutate data like this: You have no way of determining which data has changed since the previous copy has been over- written. Instead, you need to create a new copy of myData and change only the parts of it that need to be changed. Then you can compare the old copy of myData with the new one in shouldComponentUpdate() using triple-equals: Unfortunately, deep copies are expensive, and sometimes impossible. You can alleviate this by only copying objects that need to be changed and by reusing the objects that haven't changed. Unfortunately, in today's JavaScript this can be cumbersome: import update from 'react-addons-update'; // ES6 var update = require('react-addons-update'); // ES5 with npm myData.x.y.z = 7; // or... myData.a.b.push(9); const newData = deepCopy(myData); newData.x.y.z = 7; newData.a.b.push(9); Immutability Helpers 49
  50. 50. While this is fairly performant (since it only makes a shallow copy of log n objects and reuses the rest), it's a big pain to write. Look at all the repetition! This is not only annoying, but also provides a large surface area for bugs. update() {#update} update() provides simple syntactic sugar around this pattern to make writing this code easier. This code becomes: While the syntax takes a little getting used to (though it's inspired by MongoDB's query language) there's no redundancy, it's statically analyzable and it's not much more typing than the mutative version. The $ -prefixed keys are called commands. The data structure they are "mutating" is called the target. Available Commands {$push: array} push() all the items in array on the target. {$unshift: array} unshift() all the items in array on the target. {$splice: array of arrays} for each item in arrays call splice() on the target with the parameters provided by the item. {$set: any} replace the target entirely. {$merge: object} merge the keys of object with the target. {$apply: function} passes in the current value to the function and updates it with the new returned value. Examples Simple push initialArray is still [1, 2, 3] . const newData = extend(myData, { x: extend(myData.x, { y: extend(myData.x.y, {z: 7}), }), a: extend(myData.a, {b: myData.a.b.concat(9)}) }); import update from 'react-addons-update'; const newData = update(myData, { x: {y: {z: {$set: 7}}}, a: {b: {$push: [9]}} }); const initialArray = [1, 2, 3]; const newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4] react 50
  51. 51. Nested collections This accesses collection 's index 2 , key a , and does a splice of one item starting from index 1 (to remove 17 ) while inserting 13 and 14 . Updating a value based on its current one (Shallow) Merge const collection = [1, 2, {a: [12, 17, 15]}]; const newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}}); // => [1, 2, {a: [12, 13, 14, 15]}] const obj = {a: 5, b: 3}; const newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}}); // => {a: 5, b: 6} // This is equivalent, but gets verbose for deeply nested collections: const newObj2 = update(obj, {b: {$set: obj.b * 2}}); const obj = {a: 5, b: 3}; const newObj = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7} Immutability Helpers 51
  52. 52. Add-Ons Hinweis: React.addons ist seit React v15.5 veraltet. Die Add-Ons sind in ein separates Modul ver- schoben worden und einige von ihnen nicht mehr dem neusten Stand. React Add-Ons sind eine Ansammlung von nützlichen Modulen für das Erstellen von React-Apps. Sie sollten aber als "experimentell" betrachtet werden, da es sein kann, dass sie sich häu- figer als React-Core ändern. createFragment , um eine Menge von mit Schlüssel versehenden Kind-Elementen zu erstellen. Die unten stehenden Add-Ons sind nur in der Entwicklungsversion (nicht minimiert und optimiert) von React integriert: Perf , ein Tool um Optimierungsmöglickeiten in der Performance zu finden. ReactTestUtils , kleine einfache Hilfsmittel zum Schreiben von Tests. Add-on Altlasten Die unten stehenden Add-Ons gelten als Altlasten aus vorherigen Versionen. Sie werden wahr- scheinlich noch in zukünftigen React-Versionen funktionieren, aber nicht mehr aktiv weiterentwickelt. PureRenderMixin . Benutze stattdessen React.PureComponent . shallowCompare , eine Hilfsfunktion, die dich durch das oberflächliche Vergleichen von props und states entscheiden lässt, ob eine Komponente aktualisiert werden soll oder nicht. Wir empfehlen dir aber stattdessen lieber React.PureComponent zu benutzen. update . Benutze stattdessen kolodny/immutability-helper . ReactDOMFactories , vorkonfigurierte DOM-Factories um es einfacher zu machen, React ohne JSX zu verwenden. Veraltete Add-Ons LinkedStateMixin ist veraltet. TransitionGroup und CSSTransitionGroup sind veraltet, da sie durch ein Modul der Com- munity ersetzt worden sind. React mit Add-Ons verwenden Du kannst die Add-Ons einzeln über npm (z. B. npm install react-addons-create-fragment ) installieren und importieren: react 52
  53. 53. Du kannst react-with-addons.js anstelle von react.js benutzen, wenn du React 15 oder ei- ner frühere Version über ein CDN beziehst. Die Add-Ons werden über React.addons global verfügbar sein (z. B. React.addons.TestUtils ). import createFragment from 'react-addons-create-fragment'; // ES6 var createFragment = require('react-addons-create-fragment'); // ES5 mit npm <script src="https://unpkg.com/react@15/dist/react-with-addons.js"></script> Add-Ons 53
  54. 54. CDN Links React und ReactDOM sind beide über CDNs verfügbar. Diese beiden Versionen sind nur zu Entwicklung angedacht und nicht für den Live-Einsatz in Pro- duktivsystemen. Für diesen Gebrauch haben wir extra verkleinerte und optimierte Versionen von React bereitgestellt: Ersetze 18 mit einer gültigen Versionsnummer um eine bestimmte Version von react oder re‐ act-dom zu laden. Warum das crossorigin Attribut? Wir empfehlen dir, wenn du React von einem CDN beziehst, dass du das crossorigin gesetzt lässt oder setzt: Wir empfehlen außerdem zu überprüfen ob das verwendete CDN den Access-Control-Allow- Origin: * HTTP header gesetzt hat: Access-Control-Allow-Origin: * Dies ermöglicht dir ab React 16 eine bessere Fehlerbehandlung. <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></scrip <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script> <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></sc <script crossorigin src="..."></script> react 54
  55. 55. Code-Aufteilung Bundling Die meisten React Anwendungen werden ihre Dateien durch Tools wie Webpack, Rollup oder Browserify zusammengeführt haben. Bundling nennt sich der Prozess, in dem importierte Dateien zu einer Datei zusammengefügt werden: ein "Bündel (engl. bundle)". Dieses Bundle kann dann in eine Webseite eingebettet werden um eine komplette Anwendung auf einmal zu laden. Beispiel App: Bündel: Hinweis: Deine Bundles werden am Ende ganz anders aussehen als das hier. Wenn du Create React App, Next.js, Gatsby, oder ein ähnliches Tool benutzt, wirst du ein Web- pack-Setup haben welches sofort einsatzbereit ist um deine Anwendung zu bundlen. Wenn nicht, musst du das Bundling selbst einrichten. Siehe z. B. die Abschnitte Installation und Erste Schritte in der Webpack-Dokumentation. Code-Splitting Bundling ist großartig, aber sobald deine Anwendung wächst, wird dein Bundle es auch. Insbe- sondere wenn du größere Bibliotheken von Drittanbietern einbeziehst. Du musst ein Auge auf den Code haben, den du im Bundle hast, damit du ihn nicht versehentlich so groß machst und deine Anwendung zu lange zum Laden benötigt. // app.js import { add } from './math.js'; console.log(add(16, 26)); // 42 // math.js export function add(a, b) { return a + b; } function add(a, b) { return a + b; } console.log(add(16, 26)); // 42 Code-Aufteilung 55
  56. 56. Um zu vermeiden, dass du mit einem großen Bundle endest, ist es gut, dem Problem voraus zu sein und mit dem "Splitten" (dt. aufteilen) deines Bundles zu beginnen. Code-Splitting ist eine Funktion, die von Bundlern wie Webpack, Rollup und Browserify unterstützt wird (via factor- bundle). Durch sie werden mehrere Bundles erzeugt, die zur Laufzeit dynamisch geladen werden können. Code-Splitting deiner Anwendung kann dir helfen genau die Dinge "lazy zu laden", die der Benut- zer gerade benötigt, was die Performance deiner Anwendung drastisch verbessern kann. Du hast zwar die Gesamtmenge an Code nicht verringert, aber du hast das Laden von Code vermieden, den der Benutzer möglicherweise nie brauchen wird. Zusätzlich reduzierst du die Menge an Code beim initialen Laden. import() {#import} Der beste Weg Code-Splitting in deiner Anwendung einzuführen, ist durch die dynamische im‐ port() -Syntax. Vorher: Nachher: Wenn Webpack auf diese Syntax stößt, fängt es automatisch mit dem Code-Splitting deiner An- wendung an. Wenn du Create-React-App verwendest, ist dies alles vorkonfiguriert und du kannst [direkt loslegen]((https://create-react-app.dev/docs/code-splitting/). Next.js unterstützt dies auch direkt out of the box. Wenn du Webpack selbst einrichtest, wirst du wahrschenlich Webpack's Code-Splitting Leitfaden lesen wollen. Deine Webpack-Konfiguration sollte in etwa so aussehen. Wenn du Babel verwendest, müsstest du sicherstellen, dass Babel die Dynamic-Import-Syntax parsen kann, sie aber nicht transformiert. Für all das benötigst du @babel/plugin-syntax-dyna- mic-import. React.lazy {#reactlazy} Mit der Funktion React.lazy kannst du einen dynamischen Import als reguläre Komponente rendern. Before: import { add } from './math'; console.log(add(16, 26)); import("./math").then(math => { console.log(math.add(16, 26)); }); import OtherComponent from './OtherComponent'; react 56
  57. 57. After: Dadurch wird automatisch das Bundle geladen, dass OtherComponent enthält, wenn die Kompo- nente das erste Mal gerendert wird. React.lazy nimmt eine Funktion entgegen, die ein dynamisches import() aufrufen muss. Dies muss ein Promise zurückgeben, welches eine Modul auflöst, dass eine React-Komponenten im default Export enthält. Die Lazy-Komponente sollte dann in einer Suspense -Komponente gerendert werden, was es uns ermöglicht ein wenig Fallback-Inhalt anzuzeigen (z. B. eine Ladeanzeige), während wir darauf warten, dass die Lazy-Komponente lädt. Das fallback -Prop akzeptiert jedes React-Element, das du rendern möchtest, während du drauf wartest, dass die Komponente geladen wird. Du kannst die Suspense -Komponente überall über der Lazy-Komponente platzieren. Du kannst sogar mehrere Lazy-Komponenten mit einer einzigen Suspense -Komponente umhüllen. const OtherComponent = React.lazy(() => import('./OtherComponent')); import React, { Suspense } from 'react'; const OtherComponent = React.lazy(() => import('./OtherComponent')); function MyComponent() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <OtherComponent /> </Suspense> </div> ); } import React, { Suspense } from 'react'; const OtherComponent = React.lazy(() => import('./OtherComponent')); const AnotherComponent = React.lazy(() => import('./AnotherComponent')); function MyComponent() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <section> <OtherComponent /> <AnotherComponent /> </section> </Suspense> </div> ); } Code-Aufteilung 57
  58. 58. Avoiding fallbacks Any component may suspend as a result of rendering, even components that were already shown to the user. In order for screen content to always be consistent, if an already shown component suspends, React has to hide its tree up to the closest <Suspense> boundary. However, from the user's perspective, this can be disorienting. Consider this tab switcher: In this example, if tab gets changed from 'photos' to 'comments' , but Comments suspends, the user will see a glimmer. This makes sense because the user no longer wants to see Photos , the Comments component is not ready to render anything, and React needs to keep the user ex- perience consistent, so it has no choice but to show the Glimmer above. However, sometimes this user experience is not desirable. In particular, it is sometimes better to show the "old" UI while the new UI is being prepared. You can use the new startTransition API to make React do this: Here, you tell React that setting tab to 'comments' is not an urgent update, but is a transition that may take some time. React will then keep the old UI in place and interactive, and will switch to showing <Comments /> when it is ready. See Transitions for more info. import React, { Suspense } from 'react'; import Tabs from './Tabs'; import Glimmer from './Glimmer'; const Comments = React.lazy(() => import('./Comments')); const Photos = React.lazy(() => import('./Photos')); function MyComponent() { const [tab, setTab] = React.useState('photos'); function handleTabSelect(tab) { setTab(tab); }; return ( <div> <Tabs onTabSelect={handleTabSelect} /> <Suspense fallback={<Glimmer />}> {tab === 'photos' ? <Photos /> : <Comments />} </Suspense> </div> ); } function handleTabSelect(tab) { startTransition(() => { setTab(tab); }); } react 58
  59. 59. Fehlergrenzen Wenn das andere Modul nicht lädt (z. B. aufgrund eines Netzwerkausfalls), löst es einen Fehler aus. Du kannst diese Fehler behandeln, um eine schönere Benutzererfahrung zu bieten und die Wiederherstellung mit Fehlergrenzen zu verwalten. Sobald du deine Fehlergrenze erstellt hast, kannst du sie überall oberhalb deinen Lazy-Komponenten verwenden, um einen Fehlerstatus an- zuzeigem, wenn ein Netzwerkfehler vorliegt. Routen basiertes Code-Splitting Die Entscheidung wo in deiner Anwendung Code-Splitting einzuführen ist, kann etwas schwierig sein. Du solltest sicherstellen, dass du Orte wählst, die die Bundles gleichmäßig splitten, aber nicht die Benutzererfahrung beeinträchtigen. Ein guter Ausgangspunkt sind Routen. Die meisten Leute im Web sind es gewohnt Page-Transiti- ons zu erstellen, die einige Zeit zum Laden benötigen. Sie neigen auch dazu, die gesamte Seite auf einmal neu zu rendern, so dass die Benutzer wahrscheinlich nicht gleichzeitig mit anderen Elementen auf der Seite interagieren. Hier ist ein Beispiel wie du ein routenbasiertes Code-Splitting in deiner Anwendung mit Hilfe von Bibliotheken, wie React Router mit React.lazy einrichtest. import React, { Suspense } from 'react'; import MyErrorBoundary from './MyErrorBoundary'; const OtherComponent = React.lazy(() => import('./OtherComponent')); const AnotherComponent = React.lazy(() => import('./AnotherComponent')); const MyComponent = () => ( <div> <MyErrorBoundary> <Suspense fallback={<div>Loading...</div>}> <section> <OtherComponent /> <AnotherComponent /> </section> </Suspense> </MyErrorBoundary> </div> ); import React, { Suspense, lazy } from 'react'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; const Home = lazy(() => import('./routes/Home')); const About = lazy(() => import('./routes/About')); const App = () => ( <Router> <Suspense fallback={<div>Lade...</div>}> <Routes> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> </Routes> Code-Aufteilung 59
  60. 60. Benannte Exporte React.lazy unterstützt derzeit nur default Exporte. Wenn das Modul, das du importieren möchtest, benannte exports enthält, kannst du ein Zwischenmodul erstellen, das es als de‐ fault wieder exportiert. Dies stellt sicher, dass das Tree-Shaking weiter funktioniert und es kei- ne unbenutzten Komponenten mit einbezieht. </Suspense> </Router> ); // ManyComponents.js export const MyComponent = /* ... */; export const MyUnusedComponent = /* ... */; // MyComponent.js export { MyComponent as default } from "./ManyComponents.js"; // MyApp.js import React, { lazy } from 'react'; const MyComponent = lazy(() => import("./MyComponent.js")); react 60
  61. 61. Codebase Overview This section will give you an overview of the React codebase organization, its conventions, and the implementation. If you want to contribute to React we hope that this guide will help you feel more comfortable making changes. We don't necessarily recommend any of these conventions in React apps. Many of them exist for historical reasons and might change with time. Top-Level Folders After cloning the React repository, you will see a few top-level folders in it: packages contains metadata (such as package.json ) and the source code ( src subdirec- tory) for all packages in the React repository. If your change is related to the code, the src subdirectory of each package is where you'll spend most of your time. fixtures contains a few small React test applications for contributors. build is the build output of React. It is not in the repository but it will appear in your React clone after you build it for the first time. The documentation is hosted in a separate repository from React. There are a few other top-level folders but they are mostly used for the tooling and you likely won't ever encounter them when contributing. Colocated Tests We don't have a top-level directory for unit tests. Instead, we put them into a directory called __tests__ relative to the files that they test. For example, a test for setInnerHTML.js is located in __tests__/setInnerHTML-test.js right next to it. Warnings and Invariants The React codebase uses console.error to display warnings: Warnings are only enabled in development. In production, they are completely stripped out. If you need to forbid some code path from executing, use invariant module instead: if (__DEV__) { console.error('Something is wrong.'); } var invariant = require('invariant'); invariant( Codebase Overview 61
  62. 62. The invariant is thrown when the invariant condition is false . "Invariant" is just a way of saying "this condition always holds true". You can think about it as making an assertion. It is important to keep development and production behavior similar, so invariant throws both in development and in production. The error messages are automatically replaced with error codes in production to avoid negatively affecting the byte size. Development and Production You can use __DEV__ pseudo-global variable in the codebase to guard development-only blocks of code. It is inlined during the compile step, and turns into process.env.NODE_ENV !== 'production' checks in the CommonJS builds. For standalone builds, it becomes true in the unminified build, and gets completely stripped out with the if blocks it guards in the minified build. Flow We recently started introducing Flow checks to the codebase. Files marked with the @flow anno- tation in the license header comment are being typechecked. We accept pull requests adding Flow annotations to existing code. Flow annotations look like this: When possible, new code should use Flow annotations. You can run yarn flow locally to check your code with Flow. Multiple Packages React is a monorepo. Its repository contains multiple separate packages so that their changes can be coordinated together, and issues live in one place. 2 + 2 === 4, 'You shall not pass!' ); if (__DEV__) { // This code will only run in development. } ReactRef.detachRefs = function( instance: ReactInstance, element: ReactElement | string | number | null | false, ): void { // ... } react 62
  63. 63. React Core The "core" of React includes all the top-level React APIs, for example: React.createElement() React.Component React.Children React core only includes the APIs necessary to define components. It does not include the reconciliation algorithm or any platform-specific code. It is used both by React DOM and React Native components. The code for React core is located in packages/react in the source tree. It is available on npm as the react package. The corresponding standalone browser build is called react.js , and it exports a global called React . Renderers React was originally created for the DOM but it was later adapted to also support native platforms with React Native. This introduced the concept of "renderers" to React internals. Renderers manage how a React tree turns into the underlying platform calls. Renderers are also located in packages/ : React DOM Renderer renders React components to the DOM. It implements top-level React‐ DOM APIs and is available as react-dom npm package. It can also be used as standalone browser bundle called react-dom.js that exports a ReactDOM global. React Native Renderer renders React components to native views. It is used internally by Re- act Native. React Test Renderer renders React components to JSON trees. It is used by the Snapshot Tes- ting feature of Jest and is available as react-test-renderer npm package. The only other officially supported renderer is react-art . It used to be in a separate GitHub re- pository but we moved it into the main source tree for now. Note: Technically the react-native-renderer is a very thin layer that teaches React to interact with React Native implementation. The real platform-specific code managing the native views lives in the React Native repository together with its components. Reconcilers Even vastly different renderers like React DOM and React Native need to share a lot of logic. In particular, the reconciliation algorithm should be as similar as possible so that declarative rende- ring, custom components, state, lifecycle methods, and refs work consistently across platforms. Codebase Overview 63
  64. 64. To solve this, different renderers share some code between them. We call this part of React a "re- conciler". When an update such as setState() is scheduled, the reconciler calls render() on components in the tree and mounts, updates, or unmounts them. Reconcilers are not packaged separately because they currently have no public API. Instead, they are exclusively used by renderers such as React DOM and React Native. Stack Reconciler The "stack" reconciler is the implementation powering React 15 and earlier. We have since stop- ped using it, but it is documented in detail in the next section. Fiber Reconciler The "fiber" reconciler is a new effort aiming to resolve the problems inherent in the stack reconci- ler and fix a few long-standing issues. It has been the default reconciler since React 16. Its main goals are: Ability to split interruptible work in chunks. Ability to prioritize, rebase and reuse work in progress. Ability to yield back and forth between parents and children to support layout in React. Ability to return multiple elements from render() . Better support for error boundaries. You can read more about React Fiber Architecture here and here. While it has shipped with React 16, the async features are not enabled by default yet. Its source code is located in packages/react-reconciler . Event System React implements a layer over native events to smooth out cross-browser differences. Its source code is located in packages/react-dom/src/events . What Next? Read the next section to learn about the pre-React 16 implementation of reconciler in more de- tail. We haven't documented the internals of the new reconciler yet. react 64
  65. 65. Komponenten und Props Komponenten erlauben dir deine Benutzeroberfläche in unabhängige, wiederverwendbare Teile aufzubrechen und jeden als isoliert zu betrachten. Diese Seite bietet dir eine Einführung in die Idee hinter Komponenten. Du kannst eine detailierte Komponentenbeschreibung in der API Refe- renz finden. Vom Konzept her sind Komponenten wie JavaScript-Funktionen. Sie akzeptieren beliebige Einga- ben ("props" genannnt) und geben React-Elemente zurück, welche beschreiben was auf dem Bildschirm angezeigt werden soll. Funktions- und Klassenkomponenten Der einfachste Weg eine Komponente zu definieren, ist eine JavaScript-Funktion zu schreiben: Diese Funktion ist eine gültige React-Komponente, da sie ein einziges "props"- (engl. kurz für properties) Objekt mit Daten akzeptiert und ein React-Element zurückgibt. Wir nennen dies "Funktionskomponenten", weil es buchstäblich JavaScript-Funktionen sind. Du kannst ebenfalls ES6-Klassen benutzen um Komponenten zu definieren: Die beiden obigen Komponenten sind aus der Sicht von React identisch. Funktion- und Klassen-Komponenten haben beide noch ein paar zusätzliche Eigenschaften, wel- che wir im nächsten Abschnitt besprechen. Eine Komponente rendern Bis jetzt haben wir nur React-Elemente kennengelernt, die DOM-Tags repräsentiert haben: Elemente können aber auch benutzerdefinierte Komponenten darstellen: React übergibt, wenn es ein Element als benutzerdefinierte Komponente erkennt, alle JSX Attri- bute als ein einziges Objekt. Dies sind die sogenannten "props" (Eigenschaften). function Welcome(props) { return <h1>Hallo {props.name}</h1>; } class Welcome extends React.Component { render() { return <h1>Hallo {this.props.name}</h1>; } } const element = <div />; const element = <Welcome name="Sara" />; Komponenten und Props 65
  66. 66. Zum Beispiel rendert dieser Code "Hallo Sarah" auf die Seite: Auf CodePen ausprobieren Fassen wir mal zusammen, was in diesem Beispiel passiert: 1. Wir rufen root.render() mit dem React-Element <Welcome name="Sara" /> auf. 2. React ruft die Welcome Komponente mit den Props {name: 'Sara'} auf. 3. Unsere Welcome -Komponente gibt als Ergebnis <h1>Hallo Sara</h1> zurück. 4. React aktualsiert effizient das DOM um <h1>Hallo Sara</h1> abzugleichen. Hinweis: Beginne den Namen von Komponenten immer mit einem Großbuchstaben. React behandelt Komponenten, die mit Kleinbuchstaben beginnen, als DOM-Tags. Zum Bei- spiel stellt <div /> ein HTML div-Tag dar, <Welcome /> hingegen ist eine Komponente und erfordert, dass Welcome im Scope ist. Bitte lese JSX im Detail, um mehr über diese Konvention zu erfahren. Komponenten zusammensetzen Komponenten können bei ihrer Ausgabe auf andere Komponenten verweisen. So können wir für jedes Detaillevel die selben abstrahierten Komponenten wiederverwenden. Denn sowohl Buttons, Formulare als auch Screens, werden in React-Apps allgemein als Komponenten bezeichnet. Zum Beispiel können wir die App Komponente mehrmals Welcome rendern lassen: Auf CodePen ausprobieren function Welcome(props) { return <h1>Hallo {props.name}</h1>; } const root = ReactDOM.createRoot(document.getElementById('root')); const element = <Welcome name="Sara" />; root.render(element); function Welcome(props) { return <h1>Hallo {props.name}</h1>; } function App() { return ( <div> <Welcome name="Sara" /> <Welcome name="Cahal" /> <Welcome name="Edite" /> </div> ); } react 66
  67. 67. Typischerweise haben neue React-Apps eine einzige App Komponente an erste Stelle. Wenn du aber React in ein bestehendes Projekt integrierst, fängst du wahrscheinlich von unten nach oben (bottom-up) an und erstellst Komponenten wie Button , dabei arbeitest dich Schritt für Schritt die View-Hierarchie nach oben. Komponenten auslagern Hab keine Angst vor dem Aufteilen von Komponenten in kleinere Komponenten. Nehmen wir mal als Beispiel diese Comment -Komponente: Auf CodePen ausprobieren Diese Komponente nimmt author (ein Objekt), text (ein String), und date (ein date-Objekt) als Props entgegen und beschreibt einen Kommentar auf einer Social Media Webseite. Aufgrund der Verschachtelung könnte diese Komponente schwer abänderbar sein, außerdem ist es auch schwierig einzelne Teile davon wiederzuverwenden. Lass uns doch mal ein paar Kompo- nenten daraus ziehen. Als erstes werden wir Avatar auslagern: Der Avatar muss nicht wissen, dass er in innerhalb von Comment gerendert wird. Darum geben wir dem prop einen gebräuchlicheren namen als: author und nennen es user . function Comment(props) { return ( <div className="Comment"> <div className="UserInfo"> <img className="Avatar" src={props.author.avatarUrl} alt={props.author.name} /> <div className="UserInfo-name"> {props.author.name} </div> </div> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); } function Avatar(props) { return ( <img className="Avatar" src={props.user.avatarUrl} alt={props.user.name} /> ); } Komponenten und Props 67
  68. 68. Wir empfehlen props nicht nach dem Kontext in dem sie verwenden werden, sondern aus dem sie kommen zu benennen. Wir können nun Comment ein bisschen vereinfachen: Als nächstes werden wir eine UserInfo Komponente extrahieren, welche einen Avatar neben den Namen des Benutzers rendert: Dadurch können wir Comment weiter vereinfachen: Auf CodePen ausprobieren function Comment(props) { return ( <div className="Comment"> <div className="UserInfo"> <Avatar user={props.author} /> <div className="UserInfo-name"> {props.author.name} </div> </div> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); } function UserInfo(props) { return ( <div className="UserInfo"> <Avatar user={props.user} /> <div className="UserInfo-name"> {props.user.name} </div> </div> ); } function Comment(props) { return ( <div className="Comment"> <UserInfo user={props.author} /> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); } react 68

×