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.

JS Fest 2019. Glenn Reyes. With great power comes great React hooks!

26 views

Published on

The React team has been working hard on changing the game of writing declarative components: Hooks! With React Hooks we are now able to use the capabilities of class components in functional components. In this talk we are going to discover the Hooks API and explore some exciting patterns using them.

Published in: Education
  • Be the first to comment

  • Be the first to like this

JS Fest 2019. Glenn Reyes. With great power comes great React hooks!

  1. 1. With great power comes great React Hooks! Glenn Reyes @glnnrys
  2. 2. Glenn Reyes 👪 🎸 🌎 Freelance JavaScript Engineer @glnnrys
  3. 3. Let's talk components!
  4. 4. var App = React.createClass({ getInitialState: function() { return { value: '' }; }, onChange: function(event) { this.setState({ value: event.target.value }); }, render: function() { return ( <div> <input type="text" value={this.state.value} onChange={this.onChange} /> <p>{this.state.value}</p> </div> ); }, });
  5. 5. [GIF?]
  6. 6. React.createClass({ mixins: [ReactWindowMixins.OnResize], render: function() { const { window } = this.state; return ( <div> current window size: {window.width}, {window.height} </div> ); } });
  7. 7. React.createClass({ mixins: [ReactWindowMixins.OnResize], // 🤦🤦🤦🤦🤦🤦🤦 render: function() { const { window } = this.state; return ( <div> current window size: {window.width}, {window.he
  8. 8. class App extends React.Component { state = { value: '' }; onChange = event => { this.setState({ value: event.target.value }); } render() { return ( <div> <input type="text" value={this.state.value} onChange={this.onChange} /> <p>{this.state.value}</p> </div> ) } }
  9. 9. const App = (props) => { const greeting = 'Hello'; return <div>{greeting} {props.name}!</div>; }
  10. 10. How do I add state to function components?
  11. 11. Container & Presentational Components
  12. 12. Container & Presentational Components DATA UI
  13. 13. class MyData extends React.Component { state = { value: '' }; onChange = event => { this.setState({ value: event.target.value }); } render() { return ( <MyUI value={this.state.value} onChange={this.onChange} /> ) } } const MyUI = ({ value, onChange }) => ( <div> <input type="text" value={value} onChange={onChange} /> <p>{value}</p> </div> )
  14. 14. class MyData extends React.Component { state = { value: '' }; onChange = event => { this.setState({ value: event.target.value }); } render() { return ( <MyUI value={this.state.value} onChange={this.onChange} /> ) } } const MyUI = ({ value, onChange }) => ( <div> <input type="text" value={value} onChange={onChange} /> <p>{value}</p> </div> ) class MyData extends React.Component { state = { value: '' }; onChange = event => { this.setState({ value: event.target.value }); } render() { return ( <MyUI value={this.state.value} onChange={this.onChange} /> ) } }
  15. 15. Higher Order Components!
  16. 16. const EnhancedComponent = higherOrderComponent(WrappedComponent);
  17. 17. const withInput = Component => class InputContainer extends React.Component { state = { value: '' }; onChange = event => { this.setState({ value: event.target.value }); } render() { return ( <Component value={this.state.value} onChange={this.onChange} /> ) } } const App = withInput(({ value, onChange }) => ( <div> <input type="text" value={value} onChange={onChange} /> <p>{value}</p> </div> ))
  18. 18. hoc1(hoc2(hoc3(hoc4(Component))))
  19. 19. compose( hoc1, hoc2, hoc3, hoc4 )(Component)
  20. 20. Thank god Render Props came around!
  21. 21. class DataProvider extends React.Component { state = { data: null } componentDidMount() { fetchSomeData().then(data => this.setState({ data })); } render() { return this.props.render(data); } } <DataProvider render={data => ( <h1>Hello {data.name}</h1> )}/>
  22. 22. class DataProvider extends React.Component { state = { data: null } componentDidMount() { fetchSomeData().then(data => this.setState({ data })); } render() { return this.props.render(data); } } <DataProvider render={data => ( <h1>Hello {data.name}</h1> )}/> class DataProvider extends React.Component { state = { data: null } componentDidMount() { fetchSomeData().then(data => this.setState({ data })); } render() { return this.props.render(data); } }
 
 
 
 

  23. 23. class DataProvider extends React.Component { state = { data: null } componentDidMount() { fetchSomeData().then(data => this.setState({ data })); } render() { return this.props.render(data); } } <DataProvider render={data => ( <h1>Hello {data.name}</h1> )}/> 
 
 
 
 
 
 
 return this.props.render(data);
 
 
 
 
 
 

  24. 24. class DataProvider extends React.Component { state = { data: null } componentDidMount() { fetchSomeData().then(data => this.setState({ data })); } render() { return this.props.render(data); } } <DataProvider render={data => ( <h1>Hello {data.name}</h1> )}/> 
 
 
 
 
 
 
 
 
 
 
 
 <DataProvider render={data => ( <h1>Hello {data.name}</h1> )}/>
  25. 25. class DataProvider extends React.Component { state = { data: null } componentDidMount() { fetchSomeData().then(data => this.setState({ data })); } render() { return this.props.render(data); } } <DataProvider render={data => ( <h1>Hello {data.name}</h1> )}/> 
 
 
 
 
 
 
 
 
 
 
 
 data => ( <h1>Hello {data.name}</h1> )
  26. 26. class DataProvider extends React.Component { state = { data: null } componentDidMount() { fetchSomeData().then(data => this.setState({ data })); } render() { return this.props.children(data); } } <DataProvider> {data => ( <h1>Hello {data.name}</h1> )} </DataProvider>
  27. 27. https://medium.com/@jackyef/react-hooks-why-we-should-embrace-it-86e408663ad6
  28. 28. Hooks! 🎉
  29. 29. What are React Hooks?
  30. 30. Hooks let you use state and other React features
 without writing a class!
  31. 31. Hooks let you use state and other React features
 with just function components!
  32. 32. import React, { useState } from 'react'; function Example() { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
  33. 33. ✅ New feature as of React 16.8 ✅ Completely opt-in ✅ No breaking changes ✅ Fully backwards compatible
  34. 34. Why React Hooks?
  35. 35. Better reuse and primitive for stateful logic between components
  36. 36. class Example extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } componentDidMount() { document.title = `You clicked ${this.state.count} times`; } componentDidUpdate() { document.title = `You clicked ${this.state.count} times`; } render() { return ( <div> <p>You clicked {this.state.count} times</p> <button onClick={() => this.setState({ count: this.state.count + 1 })}> Click me </button> </div> ); } }
  37. 37. class Example extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } componentDidMount() { document.title = `You clicked ${this.state.count} times`; } componentDidUpdate() { document.title = `You clicked ${this.state.count} times`; } render() { return ( <div> <p>You clicked {this.state.count} times</p> <button onClick={() => this.setState({ count: this.state.count + 1 })}> Click me </button> </div> ); } }
  38. 38. function Example() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
  39. 39. class FriendStatusWithCounter extends React.Component { constructor(props) { super(props); this.state = { count: 0, isOnline: null }; this.handleStatusChange = this.handleStatusChange.bind(this); } componentDidMount() { document.title = `You clicked ${this.state.count} times`; ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } componentDidUpdate() { document.title = `You clicked ${this.state.count} times`; } componentWillUnmount() { ChatAPI.unsubscribeFromFriendStatus( this.props.friend.id, this.handleStatusChange ); } handleStatusChange(status) { this.setState({ isOnline: status.isOnline }); } // ...
  40. 40. function FriendStatusWithCounter(props) { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); const [isOnline, setIsOnline] = useState(null); useEffect(() => { function handleStatusChange(status) { setIsOnline(status.isOnline); } ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; }); // ... }
  41. 41. Hooks lets us organize logic into reusable isolated units
  42. 42. No more wrapper hell
  43. 43. DEMO TIME!
  44. 44. What will happen to React classes?
  45. 45. Nothing.
  46. 46. How will hooks affect the core concepts of React?
  47. 47. ✅ Everything you already know won't change ✅ Hooks provide a more direct API 👉 props 👉 state 👉 context 👉 refs 👉 lifecycle
  48. 48. 😄 No more constructor 😄 No more bindings 😄 No more this 😄 Less code 😄 Cleaner code 😓 Learning curve 😓 Bigger React API surface 😓 Not all covered (yet) 😓 There are some rules
  49. 49. ☝ Only from React functions ☝ Only on top level
  50. 50. Hooks rely on call order.
  51. 51. function Form() { // 1. Use the name state variable const [name, setName] = useState('Mary'); // 2. Use an effect for persisting the form useEffect(function persistForm() { localStorage.setItem('formData', name); }); // 3. Use the surname state variable const [surname, setSurname] = useState('Poppins'); // 4. Use an effect for updating the title useEffect(function updateTitle() { document.title = name + ' ' + surname; }); // ... }
  52. 52. // ------------ // First render // ------------ useState('Mary') // 1. Initialize name state variable with 'Mary' useEffect(persistForm) // 2. Add an effect for persisting the form useState('Poppins') // 3. Initialize surname state variable useEffect(updateTitle) // 4. Add an effect for updating the title // ------------- // Second render // ------------- useState('Mary') // 1. Read name state variable (argument ignored) useEffect(persistForm) // 2. Replace the effect for persisting the form useState('Poppins') // 3. Read surname state variable (argument ignored) useEffect(updateTitle) // 4. Replace the effect for updating the title // ...
  53. 53. // 🔴 We're breaking the rule by using a Hook in a condition if (name !== '') { useEffect(function persistForm() { localStorage.setItem('formData', name); }); }
  54. 54. useState('Mary') // 1. Read name state variable (argument ignored) // useEffect(persistForm) // 🔴 This Hook was skipped! useState('Poppins') // 🔴 2 (but was 3). Fail to read the surname state useEffect(updateTitle) // 🔴 3 (but was 4). Fail to replace the effect
  55. 55. useEffect(function persistForm() { // 👍 We're not breaking the first rule anymore if (name !== '') { localStorage.setItem('formData', name); } });
  56. 56. When to useReducer over  useState?
  57. 57. Start with useState when building new components
  58. 58. Switch to useReducer on larger state shapes
  59. 59. How about tooling?
  60. 60. eslint-plugin-react-hooks "react-hooks/rules-of-hooks": "error", "react-hooks/exhaustive-deps": "warn",
  61. 61. How to do I test React Hooks?
  62. 62. You don't.
  63. 63. Test the component as usual.
  64. 64. @glnnrys 🔗 reactjs.org/hooks 🔗 nikgraf.github.io/react-hooks 🔗 github.com/rehooks/awesome-react-hooks 🔗 codesandbox.io/s/github/glennreyes/hooks-demo
  65. 65. Glenn Reyes @glnnrys Thank you! 🔗 reactjs.org/hooks 🔗 nikgraf.github.io/react-hooks 🔗 github.com/rehooks/awesome-react-hooks 🔗 codesandbox.io/s/github/glennreyes/hooks-demo

×