Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

of

Integrating React.js with PHP projects Slide 1 Integrating React.js with PHP projects Slide 2 Integrating React.js with PHP projects Slide 3 Integrating React.js with PHP projects Slide 4 Integrating React.js with PHP projects Slide 5 Integrating React.js with PHP projects Slide 6 Integrating React.js with PHP projects Slide 7 Integrating React.js with PHP projects Slide 8 Integrating React.js with PHP projects Slide 9 Integrating React.js with PHP projects Slide 10 Integrating React.js with PHP projects Slide 11 Integrating React.js with PHP projects Slide 12 Integrating React.js with PHP projects Slide 13 Integrating React.js with PHP projects Slide 14 Integrating React.js with PHP projects Slide 15 Integrating React.js with PHP projects Slide 16 Integrating React.js with PHP projects Slide 17 Integrating React.js with PHP projects Slide 18 Integrating React.js with PHP projects Slide 19 Integrating React.js with PHP projects Slide 20 Integrating React.js with PHP projects Slide 21 Integrating React.js with PHP projects Slide 22 Integrating React.js with PHP projects Slide 23 Integrating React.js with PHP projects Slide 24 Integrating React.js with PHP projects Slide 25 Integrating React.js with PHP projects Slide 26 Integrating React.js with PHP projects Slide 27 Integrating React.js with PHP projects Slide 28 Integrating React.js with PHP projects Slide 29 Integrating React.js with PHP projects Slide 30 Integrating React.js with PHP projects Slide 31 Integrating React.js with PHP projects Slide 32 Integrating React.js with PHP projects Slide 33 Integrating React.js with PHP projects Slide 34 Integrating React.js with PHP projects Slide 35 Integrating React.js with PHP projects Slide 36 Integrating React.js with PHP projects Slide 37 Integrating React.js with PHP projects Slide 38 Integrating React.js with PHP projects Slide 39 Integrating React.js with PHP projects Slide 40 Integrating React.js with PHP projects Slide 41 Integrating React.js with PHP projects Slide 42 Integrating React.js with PHP projects Slide 43 Integrating React.js with PHP projects Slide 44 Integrating React.js with PHP projects Slide 45 Integrating React.js with PHP projects Slide 46 Integrating React.js with PHP projects Slide 47 Integrating React.js with PHP projects Slide 48 Integrating React.js with PHP projects Slide 49 Integrating React.js with PHP projects Slide 50 Integrating React.js with PHP projects Slide 51 Integrating React.js with PHP projects Slide 52 Integrating React.js with PHP projects Slide 53 Integrating React.js with PHP projects Slide 54 Integrating React.js with PHP projects Slide 55 Integrating React.js with PHP projects Slide 56 Integrating React.js with PHP projects Slide 57 Integrating React.js with PHP projects Slide 58 Integrating React.js with PHP projects Slide 59 Integrating React.js with PHP projects Slide 60 Integrating React.js with PHP projects Slide 61 Integrating React.js with PHP projects Slide 62 Integrating React.js with PHP projects Slide 63 Integrating React.js with PHP projects Slide 64 Integrating React.js with PHP projects Slide 65 Integrating React.js with PHP projects Slide 66 Integrating React.js with PHP projects Slide 67 Integrating React.js with PHP projects Slide 68 Integrating React.js with PHP projects Slide 69 Integrating React.js with PHP projects Slide 70 Integrating React.js with PHP projects Slide 71 Integrating React.js with PHP projects Slide 72 Integrating React.js with PHP projects Slide 73 Integrating React.js with PHP projects Slide 74 Integrating React.js with PHP projects Slide 75 Integrating React.js with PHP projects Slide 76 Integrating React.js with PHP projects Slide 77 Integrating React.js with PHP projects Slide 78 Integrating React.js with PHP projects Slide 79 Integrating React.js with PHP projects Slide 80 Integrating React.js with PHP projects Slide 81 Integrating React.js with PHP projects Slide 82 Integrating React.js with PHP projects Slide 83 Integrating React.js with PHP projects Slide 84 Integrating React.js with PHP projects Slide 85 Integrating React.js with PHP projects Slide 86 Integrating React.js with PHP projects Slide 87 Integrating React.js with PHP projects Slide 88 Integrating React.js with PHP projects Slide 89 Integrating React.js with PHP projects Slide 90 Integrating React.js with PHP projects Slide 91 Integrating React.js with PHP projects Slide 92 Integrating React.js with PHP projects Slide 93 Integrating React.js with PHP projects Slide 94 Integrating React.js with PHP projects Slide 95 Integrating React.js with PHP projects Slide 96 Integrating React.js with PHP projects Slide 97 Integrating React.js with PHP projects Slide 98 Integrating React.js with PHP projects Slide 99 Integrating React.js with PHP projects Slide 100 Integrating React.js with PHP projects Slide 101 Integrating React.js with PHP projects Slide 102 Integrating React.js with PHP projects Slide 103 Integrating React.js with PHP projects Slide 104 Integrating React.js with PHP projects Slide 105 Integrating React.js with PHP projects Slide 106 Integrating React.js with PHP projects Slide 107 Integrating React.js with PHP projects Slide 108 Integrating React.js with PHP projects Slide 109 Integrating React.js with PHP projects Slide 110 Integrating React.js with PHP projects Slide 111 Integrating React.js with PHP projects Slide 112 Integrating React.js with PHP projects Slide 113 Integrating React.js with PHP projects Slide 114 Integrating React.js with PHP projects Slide 115 Integrating React.js with PHP projects Slide 116 Integrating React.js with PHP projects Slide 117 Integrating React.js with PHP projects Slide 118 Integrating React.js with PHP projects Slide 119 Integrating React.js with PHP projects Slide 120 Integrating React.js with PHP projects Slide 121 Integrating React.js with PHP projects Slide 122 Integrating React.js with PHP projects Slide 123 Integrating React.js with PHP projects Slide 124 Integrating React.js with PHP projects Slide 125 Integrating React.js with PHP projects Slide 126 Integrating React.js with PHP projects Slide 127 Integrating React.js with PHP projects Slide 128 Integrating React.js with PHP projects Slide 129 Integrating React.js with PHP projects Slide 130 Integrating React.js with PHP projects Slide 131 Integrating React.js with PHP projects Slide 132 Integrating React.js with PHP projects Slide 133 Integrating React.js with PHP projects Slide 134 Integrating React.js with PHP projects Slide 135 Integrating React.js with PHP projects Slide 136 Integrating React.js with PHP projects Slide 137 Integrating React.js with PHP projects Slide 138 Integrating React.js with PHP projects Slide 139 Integrating React.js with PHP projects Slide 140 Integrating React.js with PHP projects Slide 141 Integrating React.js with PHP projects Slide 142 Integrating React.js with PHP projects Slide 143 Integrating React.js with PHP projects Slide 144 Integrating React.js with PHP projects Slide 145 Integrating React.js with PHP projects Slide 146 Integrating React.js with PHP projects Slide 147 Integrating React.js with PHP projects Slide 148 Integrating React.js with PHP projects Slide 149 Integrating React.js with PHP projects Slide 150 Integrating React.js with PHP projects Slide 151 Integrating React.js with PHP projects Slide 152 Integrating React.js with PHP projects Slide 153 Integrating React.js with PHP projects Slide 154 Integrating React.js with PHP projects Slide 155 Integrating React.js with PHP projects Slide 156 Integrating React.js with PHP projects Slide 157 Integrating React.js with PHP projects Slide 158 Integrating React.js with PHP projects Slide 159 Integrating React.js with PHP projects Slide 160 Integrating React.js with PHP projects Slide 161 Integrating React.js with PHP projects Slide 162 Integrating React.js with PHP projects Slide 163 Integrating React.js with PHP projects Slide 164 Integrating React.js with PHP projects Slide 165 Integrating React.js with PHP projects Slide 166 Integrating React.js with PHP projects Slide 167
Upcoming SlideShare
Redux saga: managing your side effects. Also: generators in es6
Next
Download to read offline and view in fullscreen.

5 Likes

Share

Download to read offline

Integrating React.js with PHP projects

Download to read offline

s React.js a library or a framework? In any case, it is a new way of working that represents a revolution in the way of building web projects. It has very particular characteristics that allow us, for instance, to render React code from the server side, or to include React components from Twig tags. During this talk we will present React.js, we will explore how to take advantage of it from PHP projects and we will give answers to practical problems such as universal (isomorphical) rendering and the generation of React.js forms from Symfony forms without duplication of efforts.

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

Integrating React.js with PHP projects

  1. 1. PHP UK Conference February 2017 Integrating React.js with PHP Projects Nacho Martín @nacmartin
  2. 2. My name is Nacho Martin. Almost every project needs a rich frontend, for one reason or another. We build tailor-made projects. So we have been thinking about this for some time. I write code at Limenius
  3. 3. Why (as a PHP developer) should I care about the frontend?
  4. 4. What is React.js?
  5. 5. Pour eggs in the pan The fundamental premise How to cook an omelette Buy eggs Break eggs
  6. 6. Pour eggs in the pan Beat eggs The fundamental premise How to cook an omelette Buy eggs Break eggs
  7. 7. Options: The fundamental premise
  8. 8. Options: The fundamental premise 1: Re-render everything.
  9. 9. Options: The fundamental premise 1: Re-render everything. Simple
  10. 10. Options: The fundamental premise 1: Re-render everything. Simple Not efficient
  11. 11. Options: 2: Find in the DOM where to insert elements, what to move, what to remove… The fundamental premise 1: Re-render everything. Simple Not efficient
  12. 12. Options: 2: Find in the DOM where to insert elements, what to move, what to remove… The fundamental premise 1: Re-render everything. Simple Complex Not efficient
  13. 13. Options: 2: Find in the DOM where to insert elements, what to move, what to remove… The fundamental premise 1: Re-render everything. Simple EfficientComplex Not efficient
  14. 14. Options: 2: Find in the DOM where to insert elements, what to move, what to remove… The fundamental premise 1: Re-render everything. Simple EfficientComplex Not efficient React allows us to do 1, although it does 2 behind the scenes
  15. 15. Give me a state and a render() method that depends on it and forget about how and when to render.* The fundamental premise
  16. 16. Give me a state and a render() method that depends on it and forget about how and when to render.* The fundamental premise * Unless you want more control, which is possible.
  17. 17. Click me! Clicks: 0 Our first component
  18. 18. Click me! Clicks: 1Click me! Our first component
  19. 19. Our first component import React, { Component } from 'react'; class Counter extends Component { constructor(props) { super(props); this.state = {count: 1}; } tick() { this.setState({count: this.state.count + 1}); } render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Click me!</button> <span>Clicks: {this.state.count}</span> </div> ); } } export default Counter;
  20. 20. Our first component import React, { Component } from 'react'; class Counter extends Component { constructor(props) { super(props); this.state = {count: 1}; } tick() { this.setState({count: this.state.count + 1}); } render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Click me!</button> <span>Clicks: {this.state.count}</span> </div> ); } } export default Counter; ES6 Syntax (optional but great)
  21. 21. Our first component import React, { Component } from 'react'; class Counter extends Component { constructor(props) { super(props); this.state = {count: 1}; } tick() { this.setState({count: this.state.count + 1}); } render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Click me!</button> <span>Clicks: {this.state.count}</span> </div> ); } } export default Counter; ES6 Syntax (optional but great) Initial state
  22. 22. Our first component import React, { Component } from 'react'; class Counter extends Component { constructor(props) { super(props); this.state = {count: 1}; } tick() { this.setState({count: this.state.count + 1}); } render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Click me!</button> <span>Clicks: {this.state.count}</span> </div> ); } } export default Counter; ES6 Syntax (optional but great) Set new state Initial state
  23. 23. Our first component import React, { Component } from 'react'; class Counter extends Component { constructor(props) { super(props); this.state = {count: 1}; } tick() { this.setState({count: this.state.count + 1}); } render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Click me!</button> <span>Clicks: {this.state.count}</span> </div> ); } } export default Counter; ES6 Syntax (optional but great) Set new state render(), called by React Initial state
  24. 24. Working with state
  25. 25. Working with state constructor(props) { super(props); this.state = {count: 1}; } Initial state
  26. 26. Working with state constructor(props) { super(props); this.state = {count: 1}; } Initial state this.setState({count: this.state.count + 1}); Assign state
  27. 27. Working with state constructor(props) { super(props); this.state = {count: 1}; } Initial state this.setState({count: this.state.count + 1}); Assign state this.state.count = this.state.count + 1; Just remember: avoid this
  28. 28. render() and JSX render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Clícame!</button> <span>Clicks: {this.state.count}</span> </div> ); It is not HTML, it is JSX. React transforms it internally to HTML elements. Good practice: make render() as clean as possible, only a return.
  29. 29. render() and JSX render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Clícame!</button> <span>Clicks: {this.state.count}</span> </div> ); It is not HTML, it is JSX. React transforms it internally to HTML elements. Some things change Good practice: make render() as clean as possible, only a return.
  30. 30. render() and JSX render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Clícame!</button> <span>Clicks: {this.state.count}</span> </div> ); It is not HTML, it is JSX. React transforms it internally to HTML elements. Some things change We can insert JS expressions between {} Good practice: make render() as clean as possible, only a return.
  31. 31. Thinking in React render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Click me!</button> <span>Clicks: {this.state.count}</span> </div> ); }
  32. 32. Thinking in React render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Click me!</button> <span>Clicks: {this.state.count}</span> </div> ); } Here we don’t modify state
  33. 33. Thinking in React render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Click me!</button> <span>Clicks: {this.state.count}</span> </div> ); } Here we don’t make Ajax calls
  34. 34. Thinking in React render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Click me!</button> <span>Clicks: {this.state.count}</span> </div> ); } Here we don’t calculate decimals of PI and send an e-mail with the result
  35. 35. Important: think our hierarchy
  36. 36. Important: think our hierarchy
  37. 37. Component hierarchy: props class CounterGroup extends Component { render() { return ( <div> <Counter name="amigo"/> <Counter name="señor"/> </div> ); } }
  38. 38. render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}> Click me! {this.props.name} </button> <span>Clicks: {this.state.count}</span> </div> ); } and in Counter… Component hierarchy: props class CounterGroup extends Component { render() { return ( <div> <Counter name="amigo"/> <Counter name="señor"/> </div> ); } }
  39. 39. render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}> Click me! {this.props.name} </button> <span>Clicks: {this.state.count}</span> </div> ); } and in Counter… Component hierarchy: props class CounterGroup extends Component { render() { return ( <div> <Counter name="amigo"/> <Counter name="señor"/> </div> ); } }
  40. 40. Pro tip: Stateless components const Greeter = (props) => ( <div> <div>Hi {props.name}!</div> </div> )
  41. 41. Tip: Presentational and Container components const TaskList = (props) => ( <div> {props.tasks.map((task, idx) => { <div key={idx}>{task.name}</div> })} </div> ) class TasksListContainer extends React.Component { constructor(props) { super(props) this.state = {tasks: []} } componentDidMount() { // Load data with Ajax and whatnot } render() { return <TaskList tasks={this.state.tasks}/> } }
  42. 42. Everything depends on the state, therefore we can:
  43. 43. Everything depends on the state, therefore we can: •Reproduce states,
  44. 44. Everything depends on the state, therefore we can: •Reproduce states, •Rewind,
  45. 45. Everything depends on the state, therefore we can: •Reproduce states, •Rewind, •Log state changes,
  46. 46. Everything depends on the state, therefore we can: •Reproduce states, •Rewind, •Log state changes, •Make storybooks,
  47. 47. Everything depends on the state, therefore we can: •Reproduce states, •Rewind, •Log state changes, •Make storybooks, •…
  48. 48. Learn once, write everywhere
  49. 49. What if instead of this… render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Click me!</button> <span>Clicks: {this.state.count}</span> </div> ); }
  50. 50. …we have something like this? render () { return ( <View> <ListView dataSource={dataSource} renderRow={(rowData) => <TouchableOpacity > <View> <Text>{rowData.name}</Text> <View> <SwitchIOS onValueChange={(value) => this.setMissing(item, value)} value={item.missing} /> </View> </View> </TouchableOpacity> } /> </View> ); }
  51. 51. …we have something like this? render () { return ( <View> <ListView dataSource={dataSource} renderRow={(rowData) => <TouchableOpacity > <View> <Text>{rowData.name}</Text> <View> <SwitchIOS onValueChange={(value) => this.setMissing(item, value)} value={item.missing} /> </View> </View> </TouchableOpacity> } /> </View> ); } React Native
  52. 52. React Targets •Web - react-dom •Mobile - react-native •Gl shaders - gl-react •Canvas - react-canvas •Terminal - react-blessed
  53. 53. react-blessed (terminal)
  54. 54. Setup
  55. 55. Recommended setup
  56. 56. Webpack Pros
  57. 57. Webpack • Manages dependencies Pros
  58. 58. Webpack • Manages dependencies • Allows several environments: production, development, …. Pros
  59. 59. Webpack • Manages dependencies • Allows several environments: production, development, …. • Automatic page reload (even hot reload). Pros
  60. 60. Webpack • Manages dependencies • Allows several environments: production, development, …. • Automatic page reload (even hot reload). • Can use preprocessors/“transpilers”, like Babel. Pros
  61. 61. Webpack • Manages dependencies • Allows several environments: production, development, …. • Automatic page reload (even hot reload). • Can use preprocessors/“transpilers”, like Babel. Pros Cons
  62. 62. Webpack • Manages dependencies • Allows several environments: production, development, …. • Automatic page reload (even hot reload). • Can use preprocessors/“transpilers”, like Babel. Pros Cons • It has a non trivial learning curve.
  63. 63. Webpack • Manages dependencies • Allows several environments: production, development, …. • Automatic page reload (even hot reload). • Can use preprocessors/“transpilers”, like Babel. Pros Cons • It has a non trivial learning curve. I maintain a sandbox: https://github.com/Limenius/symfony-react-sandbox
  64. 64. Insertion <div id="react-placeholder"></div> import ReactDOM from 'react-dom'; ReactDOM.render( <Counter name="amigo">, document.getElementById('react-placeholder') ); HTML JavaScript
  65. 65. Integration with PHP https://github.com/Limenius/ReactRenderer
  66. 66. https://github.com/shakacode/react_on_rails Based on
  67. 67. ReactRenderer {{ react_component('RecipesApp', {'props': props}) }} import ReactOnRails from 'react-on-rails'; import RecipesApp from './RecipesAppServer'; ReactOnRails.register({ RecipesApp }); Twig: JavaScript:
  68. 68. ReactRenderer {{ react_component('RecipesApp', {'props': props}) }} import ReactOnRails from 'react-on-rails'; import RecipesApp from './RecipesAppServer'; ReactOnRails.register({ RecipesApp }); Twig: JavaScript:
  69. 69. ReactRenderer {{ react_component('RecipesApp', {'props': props}) }} import ReactOnRails from 'react-on-rails'; import RecipesApp from './RecipesAppServer'; ReactOnRails.register({ RecipesApp }); Twig: JavaScript: <div class="js-react-on-rails-component" style="display:none" data-component-name=“RecipesApp” data-props=“[my Array in JSON]" data-trace=“false" data-dom-id=“sfreact-57d05640f2f1a”></div> Generated HTML:
  70. 70. Server-side rendering
  71. 71. Give me a state and a render() method that depends on it and forget about how and when to render. The fundamental premise
  72. 72. Give me a state and a render() method that depends on it and forget about how and when to render. The fundamental premise We can render components in the server
  73. 73. Give me a state and a render() method that depends on it and forget about how and when to render. The fundamental premise We can render components in the server • SEO friendly.
  74. 74. Give me a state and a render() method that depends on it and forget about how and when to render. The fundamental premise We can render components in the server • SEO friendly. • Faster perceived page loads.
  75. 75. Give me a state and a render() method that depends on it and forget about how and when to render. The fundamental premise We can render components in the server • SEO friendly. • Faster perceived page loads. • We can cache.
  76. 76. Client-side + Server-side {{ react_component('RecipesApp', {'props': props, rendering': 'both'}}) }} TWIG
  77. 77. Client-side + Server-side {{ react_component('RecipesApp', {'props': props, rendering': 'both'}}) }} TWIG HTML returned by the server <div id="sfreact-57d05640f2f1a"><div data-reactroot="" data-reactid="1" data-react- checksum=“2107256409"><ol class="breadcrumb" data-reactid="2"><li class="active" data- reactid=“3”>Recipes</li> … … </div>
  78. 78. Client-side + Server-side {{ react_component('RecipesApp', {'props': props, rendering': 'both'}}) }} TWIG HTML returned by the server <div id="sfreact-57d05640f2f1a"><div data-reactroot="" data-reactid="1" data-react- checksum=“2107256409"><ol class="breadcrumb" data-reactid="2"><li class="active" data- reactid=“3”>Recipes</li> … … </div> An then React in the browser takes control over the component
  79. 79. Universal applications: Options
  80. 80. Option 1: Call a node.js subprocess Make a call to node.js using Symfony Process component * Easy (if we have node.js installed). * Slow. Library: https://github.com/nacmartin/phpexecjs
  81. 81. Option 2: v8js Use PHP extension v8js * Easy (although compiling the extension and v8 is not a breeze). * Currently slow, maybe we could have v8 preloaded using php-pm so it is not destroyed after every request-response cycle. Library: https://github.com/nacmartin/phpexecjs
  82. 82. Option 3: External node.js server We have “stupid” node.js server used only to render React components. It has <100 LoC, and it doesn’t know anything about our logic. * “Annoying” (we have to keep it running, which is not super annoying either). * Faster. There is an example a dummy server for this purpose at https://github.com/Limenius/symfony-react-sandbox
  83. 83. Options 1 & 2 $renderer = new PhpExecJsReactRenderer(‘path_to/server-bundle.js’); $ext = new ReactRenderExtension($renderer, 'both'); $twig->addExtension($ext); phpexecjs detects the presence of the extension v8js, if not, calls node.js
  84. 84. Option 3 $renderer = new ExternalServerReactRenderer(‘../some_path/node.sock’); $ext = new ReactRenderExtension($renderer, 'both'); $twig->addExtension($ext);
  85. 85. The best of the two worlds In development use node.js or v8js with phpexecjs. In production use an external server. If we can cache server-side responses, even better.
  86. 86. Server side rendering, is it worth it?
  87. 87. Server side rendering, is it worth it? Sometimes yes, but it introduces complexity
  88. 88. Redux support (+very brief introduction to Redux)
  89. 89. Redux: a matter of state save Your name: John Hi, John John’s stuff
  90. 90. Redux: a matter of state save Your name: John Hi, John John’s stuff
  91. 91. Redux: a matter of state save Your name: John Hi, John John’s stuff state.name callback to change it
  92. 92. dispatch(changeName(‘John')); Component
  93. 93. dispatch(changeName(‘John')); Component changeName = (name) => { return { type: ‘CHANGE_NAME', name } } Action
  94. 94. dispatch(changeName(‘John')); Component changeName = (name) => { return { type: ‘CHANGE_NAME', name } } Action const todo = (state = {name: null}, action) => { switch (action.type) { case 'CHANGE_USER': return { name: action.name } } } Reducer
  95. 95. dispatch(changeName(‘John')); Component changeName = (name) => { return { type: ‘CHANGE_NAME', name } } Action const todo = (state = {name: null}, action) => { switch (action.type) { case 'CHANGE_USER': return { name: action.name } } } Reducer Store
  96. 96. this.props.name == ‘John';dispatch(changeName(‘John')); Component changeName = (name) => { return { type: ‘CHANGE_NAME', name } } Action const todo = (state = {name: null}, action) => { switch (action.type) { case 'CHANGE_USER': return { name: action.name } } } Reducer Store
  97. 97. Redux with ReactRenderer Sample code in https://github.com/Limenius/symfony-react-sandbox import ReactOnRails from 'react-on-rails'; import RecipesApp from './RecipesAppClient'; import recipesStore from '../store/recipesStore'; ReactOnRails.registerStore({recipesStore}) ReactOnRails.register({ RecipesApp }); Twig: JavaScript: {{ redux_store('recipesStore', props) }} {{ react_component('RecipesApp') }}
  98. 98. Redux with ReactRenderer Sample code in https://github.com/Limenius/symfony-react-sandbox import ReactOnRails from 'react-on-rails'; import RecipesApp from './RecipesAppClient'; import recipesStore from '../store/recipesStore'; ReactOnRails.registerStore({recipesStore}) ReactOnRails.register({ RecipesApp }); Twig: JavaScript: {{ redux_store('recipesStore', props) }} {{ react_component('RecipesApp') }} {{ react_component('AnotherComponent') }}
  99. 99. Share store between components
  100. 100. React React React Twig Twig React By sharing store they can share state Twig Share store between components
  101. 101. Forms, a special case
  102. 102. Dynamic forms, why? •Inside of React components. •Important forms where UX means better conversions. •Very specific forms. •Very dynamic forms that aren’t boring (see Typeform for instance).
  103. 103. Typically PHP frameworks have a Form Component
  104. 104. Typically PHP frameworks have a Form Component $form (e.g. Form Symfony Component)
  105. 105. Typically PHP frameworks have a Form Component $form (e.g. Form Symfony Component) Initial values
  106. 106. Typically PHP frameworks have a Form Component $form (e.g. Form Symfony Component) Initial values UI hints (widgets, attributes)
  107. 107. Typically PHP frameworks have a Form Component $form (e.g. Form Symfony Component) Initial values UI hints (widgets, attributes) Bind incoming data
  108. 108. Typically PHP frameworks have a Form Component $form (e.g. Form Symfony Component) Initial values UI hints (widgets, attributes) Bind incoming data Deserialize
  109. 109. Typically PHP frameworks have a Form Component $form (e.g. Form Symfony Component) Initial values UI hints (widgets, attributes) Bind incoming data Deserialize Validate
  110. 110. Typically PHP frameworks have a Form Component $form (e.g. Form Symfony Component) Initial values UI hints (widgets, attributes) Bind incoming data Deserialize Validate Return errors
  111. 111. Typically PHP frameworks have a Form Component $form (e.g. Form Symfony Component) $form->createView() (helpers in other Fws not Sf) Initial values UI hints (widgets, attributes) Bind incoming data Deserialize Validate Return errors
  112. 112. Typically PHP frameworks have a Form Component $form (e.g. Form Symfony Component) $form->createView() (helpers in other Fws not Sf) Initial values UI hints (widgets, attributes) Bind incoming data Deserialize Validate Return errors Render view
  113. 113. Typically PHP frameworks have a Form Component $form (e.g. Form Symfony Component) $form->createView() (helpers in other Fws not Sf) Initial values UI hints (widgets, attributes) Bind incoming data Deserialize Validate Return errors Render view Show errors after Submit
  114. 114. Typically PHP frameworks have a Form Component $form (e.g. Form Symfony Component) $form->createView() (helpers in other Fws not Sf) Initial values UI hints (widgets, attributes) Bind incoming data Deserialize Validate Return errors Render view Some client-side validation (HTML5) Show errors after Submit
  115. 115. Using forms in an API $form $form->createView() (helpers in other Fws not Sf) Initial values UI hints (widgets, attributes) Bind incoming data Deserialize Validate Return errors Render view Some client-side validation (HTML5) Show errors after Submit
  116. 116. …and we want more $form $form->createView() (helpers in other Fws not Sf) Initial values UI hints (widgets, attributes) Bind incoming data Deserialize Validate Return errors Render view On Submit validation Some client-side validation (HTML5)
  117. 117. …and we want more $form $form->createView() (helpers in other Fws not Sf) Initial values UI hints (widgets, attributes) Bind incoming data Deserialize Validate Return errors Render view On blur sync validation On Submit validation Some client-side validation (HTML5)
  118. 118. …and we want more $form $form->createView() (helpers in other Fws not Sf) Initial values UI hints (widgets, attributes) Bind incoming data Deserialize Validate Return errors Render view On blur sync validation On Submit validation On blur async validation Some client-side validation (HTML5)
  119. 119. …and we want more $form $form->createView() (helpers in other Fws not Sf) Initial values UI hints (widgets, attributes) Bind incoming data Deserialize Validate Return errors Render view On blur sync validation On Submit validation On blur async validation Some client-side validation (HTML5) All the dynamic goodies
  120. 120. Suppose this Symfony form public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('country', ChoiceType::class, [ 'choices' => [ 'United Kingdom' => 'gb', 'Deutschland' => 'de', 'España' => 'es', ] ]) ->add('addresses', CollectionType::class, ...); };
  121. 121. Forms rendered to HTML $form->createView(); state.usuario
  122. 122. Forms rendered to HTML $form->createView(); state.usuario
  123. 123. Forms rendered to HTML $form->createView(); submit Country: España Deutschland España Addresses: Some St.- +state.usuario
  124. 124. Forms rendered to HTML $form->createView(); submit Country: España Deutschland España Addresses: Some St.- +state.usuario POST well formed with country:’es’ and not ‘España’, ‘espana', ‘spain', ‘0’…
  125. 125. Forms rendered to HTML $form->createView(); $form->submit($request); submit Country: España Deutschland España Addresses: Some St.- +state.usuario POST well formed with country:’es’ and not ‘España’, ‘espana', ‘spain', ‘0’…
  126. 126. state.usuario Forms in APIs $form;
  127. 127. submit Country: España Deutschland España Addresses: Some St.- +state.usuario Forms in APIs $form; ✘ How do we know the visible choices or values? Read the docs!
  128. 128. submit Country: España Deutschland España Addresses: Some St.- +state.usuario Forms in APIs $form; $form->submit($request); POST “I'm Feeling Lucky” ✘ How do we know the visible choices or values? Read the docs!
  129. 129. submit Country: España Deutschland España Addresses: Some St.- +state.usuario This form should not contain extra fields!!1 Forms in APIs $form; $form->submit($request); POST “I'm Feeling Lucky” ✘ How do we know the visible choices or values? Read the docs!
  130. 130. submit Country: España Deutschland España Addresses: Some St.- +state.usuario This form should not contain extra fields!!1 The value you selected is not a valid choice!! Forms in APIs $form; $form->submit($request); POST “I'm Feeling Lucky” ✘ How do we know the visible choices or values? Read the docs!
  131. 131. submit Country: España Deutschland España Addresses: Some St.- +state.usuario This form should not contain extra fields!!1 The value you selected is not a valid choice!!One or more of the given values is invalid!! :D Forms in APIs $form; $form->submit($request); POST “I'm Feeling Lucky” ✘ How do we know the visible choices or values? Read the docs!
  132. 132. submit Country: España Deutschland España Addresses: Some St.- +state.usuario This form should not contain extra fields!!1 The value you selected is not a valid choice!!One or more of the given values is invalid!! :DMUHAHAHAHAHA!!!!! Forms in APIs $form; $form->submit($request); POST “I'm Feeling Lucky” ✘ How do we know the visible choices or values? Read the docs!
  133. 133. Define, maintain and keep in sync in triplicate Form Server API docs Form Client :_( How many devs does it take to write a form?
  134. 134. Wizard type form? “While you code this we will be preparing different versions for other use cases”
  135. 135. Case: Complex Wizard Form
  136. 136. Case: Complex Wizard Form
  137. 137. Case: Complex Wizard Form
  138. 138. What we need $form->createView(); HTML API $mySerializer->serialize($form);
  139. 139. What we need $form->createView(); HTML Serialize! Ok, into which format? API $mySerializer->serialize($form);
  140. 140. JSON Schema
  141. 141. json-schema.org
  142. 142. How does it look like { "$schema": "http://json-schema.org/draft-04/schema#", "title": "Product", "description": "A product from Acme's catalog", "type": "object", "properties": { "name": { "description": "Name of the product", "type": "string" }, "price": { "type": "number", "minimum": 0, "exclusiveMinimum": true }, "tags": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true } }, "required": ["id", "name", "price"] } Definitions Types, Validation rules :_) New resource: my-api/products/form
  143. 143. Liform & LiformBundle https://github.com/Limenius/Liform use LimeniusLiformResolver; use LimeniusLiformLiform; $resolver = new Resolver(); $resolver->setDefaultTransformers(); $liform = new Liform($resolver); $form = $this->createForm(CarType::class, $car, ['csrf_protection' => false]); $schema = json_encode($liform->transform($form));
  144. 144. Transform piece by piece {"title":"task", "type":"object", "properties":{ "name":{ "type":"string", "title":"Name", "default":"I'm a placeholder", "propertyOrder":1 }, "description":{ "type":"string", "widget":"textarea", "title":"Description", "description":"An explanation of the task", "propertyOrder":2 }, "dueTo":{ "type":"string", "title":"Due to", "widget":"datetime", "format":"date-time", "propertyOrder":3 } }, “required":[ “name", "description","dueTo"]} public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('name',TypeTextType::class, [ 'label' => 'Name', 'required' => true, 'attr' => ['placeholder' => 'I'm a placeholder’]]) ->add('description',TypeTextType::class, [ 'label' => 'Description', 'liform' => [ 'widget' => 'textarea', 'description' => 'An explanation of the task', ]]) ->add('dueTo',TypeDateTimeType::class, [ 'label' => 'Due to', 'widget' => 'single_text'] ) ; }
  145. 145. Transform piece by piece {"title":"task", "type":"object", "properties":{ "name":{ "type":"string", "title":"Name", "default":"I'm a placeholder", "propertyOrder":1 }, "description":{ "type":"string", "widget":"textarea", "title":"Description", "description":"An explanation of the task", "propertyOrder":2 }, "dueTo":{ "type":"string", "title":"Due to", "widget":"datetime", "format":"date-time", "propertyOrder":3 } }, “required":[ “name", "description","dueTo"]} public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('name',TypeTextType::class, [ 'label' => 'Name', 'required' => true, 'attr' => ['placeholder' => 'I'm a placeholder’]]) ->add('description',TypeTextType::class, [ 'label' => 'Description', 'liform' => [ 'widget' => 'textarea', 'description' => 'An explanation of the task', ]]) ->add('dueTo',TypeDateTimeType::class, [ 'label' => 'Due to', 'widget' => 'single_text'] ) ; }
  146. 146. Transform piece by piece {"title":"task", "type":"object", "properties":{ "name":{ "type":"string", "title":"Name", "default":"I'm a placeholder", "propertyOrder":1 }, "description":{ "type":"string", "widget":"textarea", "title":"Description", "description":"An explanation of the task", "propertyOrder":2 }, "dueTo":{ "type":"string", "title":"Due to", "widget":"datetime", "format":"date-time", "propertyOrder":3 } }, “required":[ “name", "description","dueTo"]} public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('name',TypeTextType::class, [ 'label' => 'Name', 'required' => true, 'attr' => ['placeholder' => 'I'm a placeholder’]]) ->add('description',TypeTextType::class, [ 'label' => 'Description', 'liform' => [ 'widget' => 'textarea', 'description' => 'An explanation of the task', ]]) ->add('dueTo',TypeDateTimeType::class, [ 'label' => 'Due to', 'widget' => 'single_text'] ) ; }
  147. 147. Transform piece by piece {"title":"task", "type":"object", "properties":{ "name":{ "type":"string", "title":"Name", "default":"I'm a placeholder", "propertyOrder":1 }, "description":{ "type":"string", "widget":"textarea", "title":"Description", "description":"An explanation of the task", "propertyOrder":2 }, "dueTo":{ "type":"string", "title":"Due to", "widget":"datetime", "format":"date-time", "propertyOrder":3 } }, “required":[ “name", "description","dueTo"]} public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('name',TypeTextType::class, [ 'label' => 'Name', 'required' => true, 'attr' => ['placeholder' => 'I'm a placeholder’]]) ->add('description',TypeTextType::class, [ 'label' => 'Description', 'liform' => [ 'widget' => 'textarea', 'description' => 'An explanation of the task', ]]) ->add('dueTo',TypeDateTimeType::class, [ 'label' => 'Due to', 'widget' => 'single_text'] ) ; }
  148. 148. Transformers Transformers extract information from each Form Field. We can extract a lot of information: •Default values and placeholders. •Field attributes. •Validation rules.
  149. 149. Also important •FormView serializer for initial values. •Form serializer that extracts errors. { "code":null, "message":"Validation Failed", "errors":{ "children":{ "name":{ "errors":[ "This value should not be equal to Beetlejuice." ] }, "description":[], "dueTo":[] } } }
  150. 150. So far we have: $form $form->createView() (helpers in other Fws not Sf) Initial values UI hints (widgets, attributes) Bind incoming data Deserialize Validate Return errors Render view On blur sync validation On Submit validation On blur async validation Some client-side validation (HTML5) All the dynamic goodies
  151. 151. Form Server API docs Form Client $form Json-schema Liform
  152. 152. Leverage json-schema: Validators let valid = ajv.validate(schema, data) if (!valid) console.log(ajv.errors) https://github.com/epoberezkin/ajv
  153. 153. Leverage json-schema: Form generators • mozilla/react-jsonschema-form: React. • limenius/liform-react: React + Redux; integrated with redux-form (we ♥ redux-form). • … • Creating our own generator is not so difficult (you typically only need all the widgets, only a subset)
  154. 154. liform-react By using redux-form we can: • Have sane and powerful representation of state in Redux. • Integrate on-blur validation, async validation & on Submit validation. • Define our own widgets/themes. • Know from the beginning that it is flexible enough.
  155. 155. liform-react import React from 'react' import { createStore, combineReducers } from 'redux' import { reducer as formReducer } from 'redux-form' import { Provider } from 'react-redux' import Liform from 'liform-react' const MyForm = () => { const reducer = combineReducers({ form: formReducer }) const store = createStore(reducer) const schema = { //… } } return ( <Provider store={store}> <Liform schema={schema} onSubmit={(v) => {console.log(v)}}/> </Provider> ) }
  156. 156. liform-react { "properties": { "name": { "title":"Task name", "type":"string", "minLength": 2 }, "description": { "title":"Description", "type":"string", "widget":"textarea" }, "dueTo": { "title":"Due to", "type":"string", "widget":"datetime", "format":"date-time" } }, "required":["name"] }
  157. 157. Form Server API docs Form Client $form Json-schema React form Liform liform-react
  158. 158. =:D $form $form->createView() Initial values UI hints (widgets, attributes) Bind incoming data Deserialize Validate Return errors Render view On blur sync validation On Submit validation On blur async validation Some client-side validation (HTML5) All the dynamic goodies
  159. 159. https://github.com/Limenius/symfony-react-sandbox Example with • Webpack • ReactRenderer/ReactBundle • Liform/LiformBudle & liform-react
  160. 160. MADRID · NOV 27-28 · 2015 Thanks! @nacmartin nacho@limenius.com http://limenius.com Formation, Consulting and Development.
  • RenatoOliveiraLucena

    Dec. 9, 2020
  • OlgaKorneeva1

    Mar. 30, 2018
  • laminiconjura

    Feb. 9, 2018
  • DevAteam

    Oct. 23, 2017
  • WerlitonCarlos

    Apr. 5, 2017

s React.js a library or a framework? In any case, it is a new way of working that represents a revolution in the way of building web projects. It has very particular characteristics that allow us, for instance, to render React code from the server side, or to include React components from Twig tags. During this talk we will present React.js, we will explore how to take advantage of it from PHP projects and we will give answers to practical problems such as universal (isomorphical) rendering and the generation of React.js forms from Symfony forms without duplication of efforts.

Views

Total views

6,774

On Slideshare

0

From embeds

0

Number of embeds

10

Actions

Downloads

73

Shares

0

Comments

0

Likes

5

×