Demystifying React for Symfony developers

Demystifying React for Symfony developers

SymfonyCon Amsterdam 2019

364d59ac0b4b4e5eee8aeb27a127d176?s=128

Titouan Galopin

November 22, 2019
Tweet

Transcript

  1. Demystifying React for Symfony developers Titouan GALOPIN

  2. 2 Titouan Galopin Product Manager SymfonyInsight insight.symfony.com

  3. Agenda 1. What’s React? 2. Components 3. Symfony integration with

    Webpack Encore 3
  4. 4 1. What’s React?

  5. 5 How should we structure Javascript applications?

  6. 6 AngularJS Vue Backbone.js Dart Ember.js Dojo Meteor ...

  7. 7 There is a consensus here: MVC, or MVVM, or

    MVW, ...
  8. 8 Models

  9. 9 { firstName: 'Titouan', lastName: 'Galopin', email: 'titouan.galopin@symfony.com' }

  10. 10 Models = Observable objects

  11. 11 Bidirectional data-binding An change in the model updates the

    view An change in the view updates the model
  12. 12 Two data sources Model View

  13. 13 This encourages mutations

  14. 14 { firstName: 'Tito', lastName: 'Galopin', email: 'titouan.galopin@symfony.com' } Model

    { firstName: 'Titouan''Tito', lastName: 'Galopin', email: 'titouan.galopin@symfony.com' } View { firstName: 'Tito' } Mutation
  15. 15 But mutations are complex

  16. 16 Complex to apply Complex to reproduce Complex to debug

  17. 17 What if we could do better?

  18. 18 The simplest way to build views is to avoid

    mutations altogether
  19. 19 React does not use mutations at all

  20. 20 Instead, it has a single data source

  21. 21 Model View Observable model Two-way data flow

  22. 22 Model Observable model Two-way data flow View React One-way

    data flow Model Dispatcher View
  23. View 23 Model Observable model Two-way data flow View React

    One-way data flow Model Dispatcher View
  24. 24 Model Observable model Two-way data flow View React One-way

    data flow Model Dispatcher View
  25. 25 But isn’t that super slow? What about user inputs?

  26. 26 We want the benefits to blow the view away

    and re-render it ... … while dealing properly with every edge cases
  27. 27 That’s React

  28. 28 React is a Javascript library for building User Interfaces

  29. 29 React is declarative render(data: array) => view: string

  30. 30 React re-renders all your view when data changes

  31. 31 2. Components

  32. 32 React’s main concept is Components

  33. 33 A component = A description of a part of

    your UI that depends on your current model
  34. 34 It’s more than a template though

  35. 35 Store Dispatcher View Each component has its own model

    and behavior This is component
  36. 36 The aim? Abstract away the implementation details of parts

    of the UI
  37. 37

  38. 38 <Autocomplete source="/api/users" onSelect={this.handleUserSelected} />

  39. 39 <Autocomplete source="/api/users" onSelect={this.handleUserSelected} /> Property

  40. 40 But how does it work?

  41. 41 A component = A state + A way to

    display that state
  42. 42 Store (Model) Dispatcher View React handles the Dispatcher and

    the Store You only implement the view and define the structure of the Store
  43. 43 The state is a single Javascript object

  44. 44 The view is described by a single render() function

  45. 45 Store (state) Initial state

  46. 46 render Store (state) View (components) Initial state

  47. 47

  48. 48 class Autocomplete extends Component { constructor() { this.state =

    { results: [] }; } }
  49. 49 class Autocomplete extends Component { // ... render() {

    return ( <ul> {this.state.results.map(function(result) { return ( <li>{result.name}</li> ); })} </ul> ); } }
  50. 50 class Autocomplete extends Component { // ... render() {

    return ( <ul> {this.state.results.map(function(result) { return ( <li>{result.name}</li> ); })} </ul> ); } } Use of the state
  51. 51 class Autocomplete extends Component { // ... render() {

    return ( <ul> {this.state.results.map(function(result) { return ( <li>{result.name}</li> ); })} </ul> ); } } Use of the state To use a property: this.props.source
  52. State = Local data that will change over time Props

    = Non-local data, read-only for the component 52
  53. If either the state or the properties change, the component

    will be re-rendered 53
  54. 54 class Autocomplete extends Component { // ... render() {

    return ( <ul> {this.state.results.map(function(result) { return ( <li>{result.name}</li> ); })} </ul> ); } }
  55. 55 class Autocomplete extends Component { // ... render() {

    return ( <ul> {this.state.results.map(function(result) { return ( <li>{result.name}</li> ); })} </ul> ); } } What’s that?!
  56. 56 JSX is a formatting language used by React to

    express a representation of views
  57. 57 It is compiled to Javascript <li className="hello"> becomes React.DOM.li({

    className: 'hello'})
  58. 58 class Autocomplete extends Component { // ... render() {

    return ( <ul> {this.state.results.map(function(result) { return ( <li>{result.name}</li> ); })} </ul> ); } } Not real HTML tags but components
  59. 59 render() returns a tree of components

  60. 60 You usually create your own tree of components RegistrationForm

    CityAutocompleteInput PhoneNumberInput HTMLTextInput HTMLTelInput
  61. 61 Now, how to update the view?

  62. 62 Instead of updates (mutations) React uses reconciliation

  63. 63 setState()

  64. 64 React compares the view representations and apply the changes

    to the DOM
  65. Tree of components before change Tree of components after change

    setState
  66. 66 Tree of components before change Tree of components after

    change setState render render View before View after
  67. 67 Tree of components before change Tree of components after

    change setState render render View before View after React compares both and apply only needed changes to the DOM
  68. 68 class Autocomplete extends Component { // ... handleChange(event) {

    api.fetchResults(event.target.value).then(results => { this.setState({ results: results }) }); } // ... render() { return ( <div> <input type="text" onChange={this.handleChange} /> // ... </div> ); } }
  69. 69 setState() merges the current state and the given data

    ...
  70. 70 … then calls recursively render() on the component and

    all its children
  71. 71 render Store (state) View (components) Initial state

  72. 72 Dispatcher (React) setState render Store (state) View (components) Initial

    state
  73. 73 Dispatcher (React) setState render Handled by React Store (state)

    View (components) Initial state
  74. 74 Now you know React!

  75. 75 3. Symfony integration with Webpack Encore

  76. 76 Webpack is a build tool It lets you manipulate

    your Javascript and CSS before using it in production (JSX, minification, …)
  77. 77 Webpack Encore wraps Webpack around a nice API to

    improve its Developer Experience
  78. 78 Webpack Encore is awesome to compile React apps to

    normal Javascript
  79. 79 composer req --dev webpack yarn install https://symfony.com/doc/current/frontend.html

  80. 80 yarn add @babel/preset-react react react-dom prop-types

  81. 81 // webpack.config.js const Encore = require( '@symfony/webpack-encore' ); Encore

    // ... .enableReactPreset(); module.exports = Encore.getWebpackConfig();
  82. 82 Once Webpack Encore is ready, you can use it

    in Twig to load React
  83. 83 // index.html.twig ... <div id="portfolio"></div> … // Output proper

    <script src="..."> tags {{ encore_entry_script_tags('app') }}
  84. 84 // app.js import ReactDOM from 'react-dom'; import {App} from

    './App.js'; ReactDOM.render( <App />, document.getElementById('portfolio') );
  85. 85 // app.js import ReactDOM from 'react-dom'; import {App} from

    './App.js'; ReactDOM.render( <App />, document.getElementById('portfolio') ); Tree of components
  86. 86 And that’s all! You can now use React into

    Symfony
  87. 87 Conclusion

  88. Thanks! 88 For any question: ▪ @titouangalopin on Twitter ▪

    titouan.galopin @symfony.com