Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Mit React UI-Komponenten für das Web entwickeln

Mit React UI-Komponenten für das Web entwickeln

React ist ein JavaScript Framework, mit dem sich auf einfache Weise wiederverwendbare UI-Komponenten für das Web entwickeln lassen. Ursprünglich von Facebook entwickelt und verwendet, steht es mittlerweile auch als Open-Source-Projekt zur Verfügung und erfreut sich zunehmender Beliebtheit.
In diesem Talk stelle ich Ihnen die grundsätzlichen Konzepte von React vor und zeige Ihnen, inwieweit sich React von anderen Frameworks wie z.B. AngularJS unterscheidet. Anhand von Codebeispielen sehen Sie, wie Sie mit React Komponenten entwickeln können, die sich sowohl auf dem Client- als auch auf dem Server rendern lassen. Dabei werden wir uns auch ansehen, wie Sie bereits heute die neuste JavaScript-Version (ECMAScript 2015) zusammen mit React einsetzen können.

4c6fc0a5e43d8e08dd0015d1133289e5?s=128

Nils Hartmann

November 10, 2015
Tweet

Transcript

  1. NILS HARTMANN | W-JAX 2015 UI-KOMPONENTEN ENTWICKELN   REACT MIT

     
  2. NILS@NILSHARTMANN.NET GitHub Twitter E-Mail

  3. A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES React

  4. SINGLE PAGE APPLICATIONS React

  5. OPEN SOURCE VON FACEBOOK HTTPS://FACEBOOK.GITHUB.IO/REACT/ React

  6. 0.3 0.14.1 rc beta alpha 05 | 2013 Open Source

    10 | 2015 Aktuelles Release „Major“-Releases
  7. BUILT WITH REACT!

  8. V in MVC

  9. W-JAX DEMO ANWENDUNG! Code: https://github.com/nilshartmann/react-example-app Demo: https://nilshartmann.github.io/react-example-app/

  10. Wiederverwendbar Hierarchisch Logik und UI KOMPONENTEN <PasswordView>! <PasswordForm>! <input>! <CheckLabelList>!

    <CheckLabel />! <CheckLabel />! </CheckLabelList>! <Label />! <Button />! </PasswordForm>! </PasswordView>!
  11. Aus Komponenten aggregiert ANWENDUNGEN <Application>! <Navigation />! <ViewContainer>! <PasswordView>! .

    . .! </PasswordView>! </ViewContainer>! </Application>!
  12. REACT Hintergrund

  13. DOM OPERATIONEN Manuelle DOM-Manipulationen Umständliche API Fehleranfällig Performance-kritisch DOM DIFF

    DIFF DIFF MODEL
  14. DATA BINDING Verbinden von Model und View Wann wird was

    gebunden? Wie funktioniert das Binding? Reihenfolge von Events?
  15. Einfachheit REACT respond to events & render UI

  16. Einfachheit respond to events & and render UI Event Zustand

    Rendern Mausklick Texteingabe Timer Serverantwort . . .
  17. Einfachheit respond to events & and render UI Event Zustand

    Rendern Mausklick Texteingabe Timer Serverantwort . . . Immer ganze Komponente rendern Kein 2-Way-Databinding Kein dirty checking
  18. RENDER UI Event Re-render

  19. Einfachheit respond to events & and render UI Event Zustand

    Rendern Mausklick Texteingabe Timer Serverantwort . . . Immer ganze Komponente rendern ? Performance?
  20. VIRTUELLER DOM VIRTUAL DOM MODEL DOM UPDATE UPDATE UPDATE React

  21. UI AS A FUNCTION ∫ (model) à UI Model mit

    allen Zuständen (Textfelder, Auswahllisten etc) Immer ein Zeitpunkt Keine Dynamik render()! render(R3)! render(R3!tdemo)! render(R3)!
  22. React PRAXIS

  23. React SCHRITT FÜR SCHRITT

  24. EINE REACT KOMPONENTE 1! HTML <div ! class="CheckLabel-unchecked">! At least

    8 characters long.! </div>!
  25. EINE REACT-KOMPONENTE 2! Komponente CheckLabel Komponentenfunktion (seit 0.14) function CheckLabel()

    {! return <div ! className="CheckLabel-unchecked">! At least 8 characters long.! </div>;! }! CheckLabel.js JSX: Statt Template-Sprache
  26. EINE REACT-KOMPONENTE 3! Übersetzter JavaScript Code React.createElement(! "div",! { className:

    "CheckLabel-unchecked" },! "At least 8 characters long."! );! Erzeugt „virtuelles“ DOM-Element
  27. KOMPONENTE RENDERN! import React from 'react';! import ReactDOM from 'react-dom';!

    ! import CheckLabel from './CheckLabel';! ! ! ReactDOM.render(<CheckLabel />, ! document.getElementById('mount'));! <html>! <body>! <div id=“mount“></div>! </body>! <script src=“dist/dist.js“></script>! </html>! app.js index.html Webpack
  28. PROPERTIES! function CheckLabel({checked, label}) {! return <div ! className=! {checked?'CheckLabel-checked':'CheckLabel-unchecked'}>!

    {label}! </div>;! }! Properties (destrukturiert) { ! checked: false, ! label: ‘At least 8 characters long.’ ! }!
  29. PROPERTIES BESCHREIBEN! function CheckLabel({checked, label}) {! // . . .!

    }! ! CheckLabel.propTypes = {! label: React.PropTypes.string.isRequired,! checked: React.PropTypes.bool! };! ! Beschreibung der Properties Überprüfung zur Laufzeit
  30. KOMPONENTEN VERWENDEN! function CheckLabelList() {! return <div> ! <CheckLabel checked={false}

    ! label='At least 8 characters long' />! <CheckLabel checked={true} ! label='Contains uppercase letters.' />! </div>;! }! ! function CheckLabel({checked, label}) {! // . . .! }! ! CheckLabelList CheckLabel
  31. LISTEN! function CheckLabelList({checks}) {! return <div>! {checks.map((c) => <CheckLabel label={c.label}!

    checked={c.checked}! key={c.label} />! )}! </div>;! }! ES5 Array.prototype.map() [! { checked: false, label: ‘At least 8 characters long.’ },! { checked: true, label: ‘Contains uppercase letters’ }! ];! Eindeutiger Schlüssel
  32. ZUSTANDSBEHAFTETE KOMPONENTEN! PasswordForm CheckLabelList Interner Zustand! CheckLabel input

  33. ZUSTAND! Event Zustand Rendern Textfeld Auswahl in Liste Checkbox Serverantwort

    . . . KEY VALUE password REACT! state Event Handler Rendern modifiziert löst aus
  34. KOMPONENTEN KLASSEN! class PasswordForm extends React.Component {! constructor(props) {! super(props);!

    }! ! componentDidMount() { . . . }! componentWillReceiveProps() { . . . }! shouldComponentUpdate() { . . . }! . . .! ! render() {! return <div>{this.props.label}</div>;! }! }! ! PasswordForm.propTypes = {! . . .! };! ! ECMAScript 2015 Klasse Properties über Konstruktor React Lifecycle Methoden Render Methode Properties über props-Objekt Property-Beschreibungen
  35. ZUSTAND UND RENDERING! class PasswordForm extends React.Component {! checkPassword(password) {

    return [ . . . ]; } ! ! onPasswordChange(input) {! this.setState({password: input});! }! ! render() {! const checks = this.checkPassword(this.state.password);! ! return . . .! <input value={this.state.password}! onChange={e=>this.onPasswordChange(e.target.value)} ! />! <CheckLabelList checks={checks} />! <Button enabled={passwordValid} />! }! }! 1. Event tritt ein 2. Zustand neu setzen input Zustand! 3. löst rendern der gesamten Komponente aus
  36. DOM UPDATES - BIG PICTURE Anwendung React Event Event Handler

    Event Handler setState render Update DOM z.B. Zeichen eingegeben Minimale Änderung Fachlicher Handler Globaler React Handler
  37. KOMMUNIKATION: PROPERTIES! PasswordForm CheckLabelList CheckLabel input div PasswordApp Button h1

    check! enabled! value! text! checks! render! Von oben nach unten: props!
  38. KOMMUNIKATION: EVENTS 1! PasswordForm CheckLabelList CheckLabel input div PasswordApp Button

    h1 event! R   Zeicheneingabe Von unten nach oben: events!
  39. KOMMUNIKATION: EVENTS 2! PasswordForm CheckLabelList CheckLabel input div PasswordApp Button

    h1 Von unten nach oben: events und callbacks! event! callback!
  40. KOMMUNIKATION: CALLBACK! class PasswordApp extends React.Component {! onSetPassword(password) { .

    . . }! ! render() {! return . . .! <PasswordForm . . .! onSetPasswordHandler={p=>this.onSetPassword(p)}! />;! }! }! ! ! class PasswordForm extends React.Component {! render() {! return . . .! <input value=“. . .” onChange=“. . .” />! <Button label=“Set new Password”! onClickHandler=! {()=>this.props.onSetPasswordHandler(this.state.password)}! />! }! }! ! PasswordForm.propTypes = {! onSetPasswordHandler: React.PropTypes.func.isRequired! }! 1. Callback übergeben 2. Callback aufrufen event! 3. Event verarbeiten (ggf. Zustand setzen)
  41. UNIT-TESTS (OHNE DOM)! import TestUtils from 'react-addons-test-utils';! ! describe('CheckLabel', ()

    => {! it('should render a "checked" label', () => {! ! const renderer = TestUtils.createRenderer();! renderer.render(! <CheckLabel label='My Label' checked={true}/>! );! ! 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“
  42. EINE „ANWENDUNG“ (BEISPIEL)! ! class App extends React.Component {! handleItemSelected(item)

    { ! this.setState({component: item.component}); ! }! ! render() {! return <div className='App'>! <NavigationBar! onItemSelected={item=>this.handleItemSelected(item)}! items={[! { label: 'Change password', component: <PasswordApp />},! { label: 'Show weather', component: <WeatherApp /> }! ]}! />! ! <MainView>! {this.state.component}! </MainView>! </div>;! }! }! Ausgewählte Komponente einfügen Navigation (Komponentenauswahl)
  43. Ökosystem bootstrap   router   material-­‐design   fer4ge  Komponenten  

    dev  tools   flux   na4ve   graphql  &  relay   AUSBLICK
  44. Mittagspause (wohlverdient!) React Router Serverzugriffe Integration von Dritt-Bibliotheken Build-Prozess Zugabe

  45. ZUGRIFF AUF NATIVEN DOM 1! Beispiel: focus() auf input-Feld aufrufen

    focus()
  46. ZUGRIFF AUF NATIVEN DOM 2! class PasswordForm extends React.Component {!

    ! componentDidMount() {! this.refs.passwordField.focus();! }! ! render() {! const password = this.state.password;! ! return <div>! <input ref=‘passwordField’ value={password} />! . . .! </div>;! }! }! Referenz anlegen React-Callback: Komponente wurde in den nativen DOM gehängt Natives DOM-Element Virtuelles DOM-Element this.refs enthält native DOM-Elemente, die mit ref ausgezeichnet wurden
  47. SERVERZUGRIFF! Interner Zustand! Löst Serverzugriff aus WeatherPanel WeatherView

  48. SERVERZUGRIFF 1! import WeatherPanel from ‘./WeatherPanel’;! ! class WeatherView extends

    React.Component {! constructor() {! super();! }! ! fetchWeather() {! const { city } = this.state;! const fetchUrl = `http://api.w.org/${city}`;! fetch(fetchUrl)! .then( response => response.json())! .then( weather => this.setState({weather}))! ;! }! ! render() {! const { city, weather } = this.state;! <input type=‘text’ value={city} onChange={. . .} />! <Button label=‘Load’ onClick={() => this.fetchWeather()}! <WeatherPanel weather={weather} />! }! }! Geladene Daten anzeigen Daten vom Server laden Zustand neu setzen (triggert Rendering) fetch-Bibliothek: https://fetch.spec.whatwg.org/
  49. SERVERZUGRIFF 2! class WeatherView extends React.Component {! constructor() {! super();!

    this.state = { city: ‘Hamburg’ };! }! ! componentDidMount() {! this.fetchWeather();! }! ! fetchWeather() { . . . }! ! render() { . . . }! }! Wetterdaten laden, sobald Komponente in DOM gehängt wurde State initialisieren
  50. INTEGRATION THIRD-PARTY-LIBS! Beispiel: D3.js ChartView ButtonBar Interner Zustand! D3.js SVG

  51. D3.JS! import d3 from ‘d3’;! ! class ChartView extends React.Component

    {! constructor() { this.state = { . . .}; }! ! increaseDrink(drink) { this.setState({ . . .}); }! ! componentDidMount() { this.renderChart(); }! componentDidUpdate() { this.renderChart(); }! ! renderChart() { ! d3.select(this.refs.chart)! .data(this.state.drinks)! .enter().append(. . .);! }! render() {! return . . .! <div ref=‘chart’></div>! <ButtonBar>! { drinks.map(d => <Button ! label={ . . .}! onClickHandler={()=>this.increaseDrink(d)} />) ! }! </ButtonBar> ! }! }! ! Diagramm (neu) zeichnen, sobald Komponente in DOM gehängt bzw dort aktualisiert wurde D3 Diagramm wird nicht in render() gezeichnet, weil hier kein natives DOM- Element Natives DOM-Element
  52. Viele ECMAScript 2015 Features Compiler notwendig ES2015 Alias: ES6

  53. BUILDPROZESS Babel is a JavaScript compiler Babel http://babeljs.io ES2015 „ES7“

    . . . ES5 Babel
  54. BUILDPROZESS Webpack https://webpack.github.io Module bundler - Erzeugt zentrales JavaScriptFile dist.js

    JS JS JS JS JS CSS PNG app.js Password.js Label.js Layout.js Webpack Babel Source-Files React.js
  55. BUILDPROZESS webpack-dev-server JS JS JS IDE/Editor Webpack Browser process serve

    reload edit watch webpack-dev-server
  56. NILS@NILSHARTMANN.NET Fragen? Vielen Dank!