Slide 1

Slide 1 text

NILS HARTMANN | JAX MAINZ | APRIL 2016 React EINSTIEG IN http://nilshartmann.net/react-talk

Slide 2

Slide 2 text

HTTP://NILSHARTMANN.NET/REACT-TALK [email protected]

Slide 3

Slide 3 text

HTTP://REACTBUCH.DE

Slide 4

Slide 4 text

SINGLE PAGE APPLICATIONS React

Slide 5

Slide 5 text

OPEN SOURCE VON FACEBOOK https://facebook.github.io/react React

Slide 6

Slide 6 text

v 15.0 AKTUELLE VERSION 0.14.8 0.3 05 | 2013 –OPEN SOURCE 05 | 2016 –NEUE VERSIONIERUNG

Slide 7

Slide 7 text

REACT IM EINSATZ

Slide 8

Slide 8 text

V in MVC NUR VIEW-SCHICHT

Slide 9

Slide 9 text

ES6+ ECMASCRIPT 2015

Slide 10

Slide 10 text

BEISPIEL ANWENDUNG Code: https://github.com/nilshartmann/react-example-app Demo: https://nilshartmann.github.io/react-example-app/

Slide 11

Slide 11 text

WIEDERVERWENDBARE KOMPONENTEN

Slide 12

Slide 12 text

ANWENDUNGEN AUS KOMPONENTEN KOMPONIERT . . . . . .

Slide 13

Slide 13 text

KOMPONENTEN React-Komponenten • werden deklarativ beschrieben • bestehen aus Logik und UI • keine Templatesprache • werden immer komplett gerendert • können auf dem Server gerendert werden

Slide 14

Slide 14 text

REACT SCHRITT FÜR SCHRITT

Slide 15

Slide 15 text

DIE JSX SPRACHERWEITERUNG Anstatt einer Template Sprache: HTML in JavaScript integrieren • Erlaubt Schreiben von HTML-artigen Ausdrücken im JavaScript-Code • Wird zu regulärem JavaScript Code compiliert(z.B. Babel, TypeScript) • Optional const name = 'Lemmy'; const greeting =

Hello, {name}

; var name = 'Lemmy‘; var greeting = React.createElement('h1', null, 'Hello, ', name); JSX Übersetztes JavaScript

Slide 16

Slide 16 text

EINE REACT KOMPONENTE: AUSGANGSSITUATION
At least 8 characters long.
HTML

Slide 17

Slide 17 text

EINE REACT KOMPONENTE: JSX
At least 8 characters long.
JSX

Slide 18

Slide 18 text

EINE REACT KOMPONENTE React.createElement( "div", { className: "CheckLabel-unchecked" }, "At least 8 characters long." ); Übersetzter JS Code (z.B. mittels Babel)

Slide 19

Slide 19 text

EINE REACT KOMPONENTE: ALS FUNKTION function CheckLabel() { return
At least 8 characters long.
; } JSX Komponentenfunktion Komponente CheckLabel

Slide 20

Slide 20 text

KOMPONENTE EINBINDEN . . .
index.html

Slide 21

Slide 21 text

KOMPONENTE EINBINDEN import React from 'react'; import ReactDOM from 'react-dom'; import CheckLabel from './CheckLabel'; ReactDOM.render( , document.getElementById('mount') ); app.js

Slide 22

Slide 22 text

KOMPONENTEN: PROPERTIES function CheckLabel(props) { return
{label}
; } { checked: false, label: ‘At least 8 characters long.’ }

Slide 23

Slide 23 text

KOMPONENTEN: PROPERTIES function CheckLabel(props) { . . . } CheckLabel.propTypes = { label: React.PropTypes.string.isRequired, checked: React.PropTypes.bool }; Properties beschreiben Überprüfung zur Laufzeit

Slide 24

Slide 24 text

KOMPONENTEN VERWENDEN function CheckLabelList() { return
; } function CheckLabel(props) { // . . . } CheckLabelList CheckLabel • Komponenten sind zusammensetzbar

Slide 25

Slide 25 text

KOMPONENTEN LISTEN function CheckLabelList(props) { return
{props.checks.map(c => ) }
; } checks: [ { checked: false, label: ‘At least 8 characters long.’ }, { checked: true, label: ‘Contains uppercase letters’ } ]

Slide 26

Slide 26 text

KOMPONENTEN KLASSEN class CheckLabelList extends React.Component { constructor(props) { super(props); } componentDidMount() { . . . } componentWillReceiveProps() { . . . } shouldComponentUpdate() { . . . } render() { return
{this.props.checks.map(c => )}
; } } CheckLabelList.propTypes = { . . . }; ECMAScript 2015 Klasse Properties über Konstruktor Lifecycle Methoden Render-Methode (pflicht) Properties über props Objekt Property-Beschreibungen

Slide 27

Slide 27 text

ZUSTAND VON KOMPONENTEN Zustand („state“): Komponenten-intern • Beispiel: Inhalt von Eingabefeld, Antwort vom Server • Objekt mit Key-Value-Paaren • Werte üblicherweise immutable • Zugriff über this.state/ this.setState() • Nur in Komponenten-Klassenverfügbar • this.setState() triggert erneutes Rendern • auch alle Unterkomponenten Zum Vergleich: Properties • Von außen übergeben • Unveränderlich • Zugriff über this.props(Key-Value-Paare)

Slide 28

Slide 28 text

BEISPIEL: EINGABEFELD PasswordForm Interner Zustand! input

Slide 29

Slide 29 text

BEISPIEL: EINGABEFELD input Zustand! class PasswordForm extends React.Component { render() { return
this.onPasswordChange(e.target.value)} /> . . .
; } onPasswordChange(newPassword) { this.setState({password: newPassword}); } } 1. Input mit Wert aus State befüllen 2. Event Listener

Slide 30

Slide 30 text

ZUSTAND: EINGABEFELD input Zustand! class PasswordForm extends React.Component { render() { return
this.onPasswordChange(e.target.value)} /> . . .
; } onPasswordChange(newPassword) { this.setState({password: newPassword}); } } 1. Input mit Wert aus State befüllen 2. Event Listener 3. Zustand neu setzen Neu rendern Event

Slide 31

Slide 31 text

ZUSTAND & RENDERING PasswordForm CheckLabelList state CheckLabel input beeinflußt Beispiel: Password Formular

Slide 32

Slide 32 text

„KLASSISCHE“ OBSERVER LÖSUNG Verbinden von Model und View • Wann wird was gebunden? • Wie genau funktioniert das Binding? • Zum Beispiel: Element in Liste oder ganze Liste • Reihenfolge von Events Wird schnell komplex, schwer zu durchschauen

Slide 33

Slide 33 text

GANZ EINFACH: ALLES RENDERN Event Re-render

Slide 34

Slide 34 text

BEISPIEL 1: PASSWORD FORMULAR class PasswordForm extends React.Component { onPasswordChange(newPassword) { this.setState({password: newPassword); } . . . render() { const password = this.state.password; const checks = this.checkPassword(password); const failedChecks = . . .; const isValidPassword = failedChecks === 0; return
this.onPasswordChange(event.target.value)} /> {failedChecks > 0 ?
{failedChecks} checks failed
:
All checks passed!
}
; } } Neu rendern Event

Slide 35

Slide 35 text

REACT: UNI DIRECTIONAL DATAFLOW class PasswordForm extends React.Component { onPasswordChange(newPassword) { this.setState({password: newPassword); } . . . render() { const password = this.state.password; const checks = this.checkPassword(password); const failedChecks = . . .; const isValidPassword = failedChecks === 0; return
this.onPasswordChange(event.target.value)} /> {failedChecks > 0 ?
{failedChecks} checks failed
:
All checks passed!
}
; } } Event Zustand Rendern RESPOND TO EVENTS & RENDER UI

Slide 36

Slide 36 text

BEISPIEL 2: SERVERZUGRIFFE Löst Serverzugriff aus WeatherPanel WeatherView State! Gleiches Prinzip, anderes Event • Daten werden (asynchron) vom Server geladen • Beim Eintreffen des Ergebnisses muss neu gerendert werden

Slide 37

Slide 37 text

BEISPIEL 2: SERVERZUGRIFFE MIT FETCH class WeatherView extends React.Component { fetchWeather() { fetch(`http://api.w.org/${this.state.city}`) .then(response => response.json()) .then(weather => this.setState({weather: weather})) ; } render() { return
this.fetchWeather()} /> this.setState({city: e.target.value})} />
; } } Daten vom Server laden Zustand setzen (Antwort vom Server) Geladene Daten anzeigen Event Neu rendern

Slide 38

Slide 38 text

HINTERGRUND: VIRTUAL DOM VIRTUAL DOM NATIVE DOM ZUSTAND UPDATE UPDATE UPDATE React render render render render

Slide 39

Slide 39 text

HINTERGRUND: VIRTUAL DOM Virtual DOM • React.createElement() liefert ein virtuelles DOM-Objekt zurück • DOM Events sind gewrappt • Trennung von Darstellung und Repräsentation Vorteile • Erlaubt performantes neu rendern der Komponente • Ausgabe in andere Formate (z.B. String) möglich • Kann auf dem Server gerendert werden (Universal Webapps) • Kann ohne DOM/Browser getestet werden

Slide 40

Slide 40 text

REACT: „UI AS A FUNCTION“ render() render(R3!demo) render(R3) render(R3) f(zustand) à UI • Es wird genau eine UI zu genau einem Zustand gerendert • Deklarativ, keine Seiteneffekte • Sehr einfaches Prinzip • Performant durch Virtual DOM

Slide 41

Slide 41 text

KOMPONENTENHIERARCHIEN Typische React Anwendungen: Hierarchisch aufgebaut • State möglichst weit oben („Container Komponenten“) • Mehrere Komponenten mit State möglich • Beim neu rendern bleibt State erhalten

Slide 42

Slide 42 text

KOMMUNIKATION ZWISCHEN KOMPONENTEN Typische React Anwendungen: Hierarchisch aufgebaut • State möglichst weit oben („Container Komponenten“) • Mehrere Komponenten mit State möglich • Beim neu rendern bleibt State erhalten • Wie wird kommuniziert?

Slide 43

Slide 43 text

KOMMUNIKATION: PROPERTIES Von oben nach unten: Properties Set Password

Slide 44

Slide 44 text

KOMMUNIKATION: DOM EVENTS Von unten nach oben: Events

Slide 45

Slide 45 text

KOMMUNIKATION: EIGENE EVENTS Von unten nach oben: Events und Callbacks • Callback-Funktion als Property • Event: Aufruf der Callback-Funktion

Slide 46

Slide 46 text

BEISPIEL: CALLBACK-FUNKTIONEN (1) class PasswordView extends React.Component { render() { return . . . this.setState(newPassword: p)} />; } } Callback-Funktion übergeben

Slide 47

Slide 47 text

BEISPIEL: CALLBACK-FUNKTIONEN (2) class PasswordView extends React.Component { render() { return . . . this.setState(newPassword: p)} />; } } class PasswordForm extends React.Component { render() { return . . . this.props.onSetPasswordHandler(this.state.password)} /> } } PasswordForm.propTypes = { onSetPasswordHandler: React.PropTypes.func.isRequired } Callback-Funktion aufrufen Callback-Funktion angeben

Slide 48

Slide 48 text

BEISPIEL: CALLBACK-FUNKTIONEN (3) class PasswordView extends React.Component { render() { return . . . this.setState(newPassword: p)} />; } } class PasswordForm extends React.Component { render() { return . . . this.props.onSetPasswordHandler(this.state.password)} /> } } PasswordForm.propTypes = { onSetPasswordHandler: React.PropTypes.func.isRequired } Callback-Funktion übergeben Callback-Funktion aufrufen „event“ Rendern Callback-Funktion angeben Rendern

Slide 49

Slide 49 text

ÖKOSYSTEM material-design Developer Tools Fertige Komponenten React Native React Router GraphQL & Relay Bootstrap Flux Architekturpattern

Slide 50

Slide 50 text

ZUSAMMENFASSUNG React • Nur View-Schicht (Komponenten) • Gut integrierbar mit anderen Frameworks • Einfache Migrationspfade möglich • JSX statt Templatesprache („HTML in JavaScript“) • Deklarative UI • Komponenten werden immer komplett gerendert • Kein 2-Wege-Databinding

Slide 51

Slide 51 text

@NILSHARTMANN Vielen Dank! Fragen? http://nilshartmann.net/react-talk

Slide 52

Slide 52 text

AUSBLICK

Slide 53

Slide 53 text

SERVERSEITIGES RENDERN (1) import React from 'react'; import ReactDOM from 'react-dom'; import PasswordView from './components/PasswordView'; ReactDOM.render( , document.getElementById('mount') ); Zur Erinnerung: Rendern auf dem Client

Slide 54

Slide 54 text

SERVERSEITIGES RENDERN (2) import React from 'react'; import ReactDOMServer from 'react-dom/server'; import PasswordView from './components/PasswordView'; const html = ReactDOMServer.renderToString(); const page = ` . . .
${html}
`; // page an Client senden Rendern auf dem Server (vereinfacht)

Slide 55

Slide 55 text

BEISPIEL: UNIT TESTS (OHNE DOM) import { expect } from 'chai'; import TestUtils from 'react-addons-test-utils'; describe('CheckLabel', () => { it('should render a "checked" label', () => { const renderer = TestUtils.createRenderer(); renderer.render( ); const tree = renderer.getRenderOutput(); expect(tree.type).to.equal('div'); expect(tree.props.className).to.equal('CheckLabel-checked'); expect(tree.props.children).to.equal('My Label'); }); }); „Shallow rendering“

Slide 56

Slide 56 text

BEISPIEL: UNIT TESTS (MIT DOM) import { expect } from 'chai'; import jsdom from 'mocha-jsdom'; import { . . . } from 'react-addons-test-utils'; describe('PasswordForm', () => { jsdom(); it('updates button', () => { const tree = renderIntoDocument( ); expect(isCompositeComponentWithType(tree, PasswordForm)).to.be.true; const inputField = findRenderedDOMComponentWithTag(tree, 'input'); const btn = findRenderedDOMComponentWithTag(tree, 'button'); Simulate.change(inputField, {target: {value: 'xxx'}}); expect(setPasswordButton.disabled).to.be.true; }); });

Slide 57

Slide 57 text

BEISPIEL: INITIALISIERUNG UND LEBENSZYKLUS class WeatherView extends React.Component { constructor() { this.state = { city: ‘Hamburg’ }; } componentDidMount() { this.fetchWeather(); } fetchWeather() { fetch(`http://api.w.org/${this.state.city}`) .then(response => response.json()) .then(weather => this.setState({weather})) ; } render() { return
this.fetchWeather()} /> this.setState({city: e.target.value})} />
; } } Zustand initialisieren Initiales laden auslösen