Lightning Fast React Apps

6e0ba5b45dafe063b98db2a1d5391433?s=47 Sia
September 22, 2017

Lightning Fast React Apps

App loading and run-time affect your bottom line. Fancy features aren’t worth anything if users leave the app out of frustration. Every second counts! React is super fast, but you could be shooting yourself in the foot with design decisions. Come learn how to make your React apps lightning fast!

Page abandonment increases with every second of load time. Also, profiling and debugging performance issues can seem like an overwhelming topic to learn. In this session, we’ll cover the usual suspects of performance issues, from the basics of using the correct build, to the fundamentals of immutable data, to higher-level tools like Perf, shouldComponentUpdate, PureComponent, and memoizing computed props in Redux.

We will both cover the concepts and walk through examples step-by-step so that by the end of this session you will feel like a React Speed Racer. You’ll get the most out of this session if you’re at least comfortable with React and ES6 syntax.

6e0ba5b45dafe063b98db2a1d5391433?s=128

Sia

September 22, 2017
Tweet

Transcript

  1. LIGHTNING Fast React Sia Karamalegos @thegreengreek

  2. Who Am I? thegreengreek on Twitter and Medium siakaramalegos on

    GitHub
  3. What are we going to talk about? 1. Why you

    should care about performance 2. Things you should always do 3. Things you should do only if you your app is too slow 4. The React Performance add-on
  4. "53% of mobile site visits are abandoned if pages take

    longer than 3 seconds to load" DoubleClick by Google, 2016 https://www.doubleclickbygoogle.com/articles/mobile-speed-matters/
  5. What about responsiveness?

  6. What things should I always do?

  7. Always use the production version of React in production! Or…

    Don’t ignore the warnings!
  8. Automatic when using Create React App… • Development version is

    used when running $ npm start and then accessing the development build hosted at localhost:3000 • Production version is used when running $ npm run build and then using the production build found in the build/ folder
  9. Declare the correct NODE_ENV in Webpack new webpack.DefinePlugin({ 'process.env': {

    NODE_ENV: JSON.stringify(process.env.NODE_ENV), }, }), ✔
  10. Always use unique and stable keys! Again… Don’t ignore the

    warnings!
  11. <!-- Scenario 1: No keys. Boo. --> <ul> <li>Sloth</li> <li>Lemur</li>

    <li>Koala</li> </ul> <!-- Adding item to top re-renders entire thing - only compares based on the index or order of elements. i.e., Lemur != Sloth --> <ul> <li>Kangaroo</li> <li>Sloth</li> <li>Lemur</li> <li>Koala</li> </ul> <!-- Scenario 2: Keys! Yay! --> <ul> <li key="sloth">Sloth</li> <li key="lemur">Lemur</li> <li key="koala">Koala</li> </ul> <!-- After list - only inserts new Kangaroo item. Way more efficient! --> <ul> <li key="kangaroo">Kangaroo</li> <li key="sloth">Sloth</li> <li key="lemur">Lemur</li> <li key="koala">Koala</li> </ul> ✘ ✔
  12. <!-- Scenario 3: Useless keys. Boo. --> <ul> <li key="1">Sloth</li>

    <li key="2">Lemur</li> <li key="3">Koala</li> </ul> <!-- After list - re-renders entire thing because item with key of 1 is different before & after, for every item. Don't accidentally do this with Array.map! --> <ul> <li key="1">Kangaroo</li> <li key="2">Sloth</li> <li key="3">Lemur</li> <li key="4">Koala</li> </ul> ✘ Make sure keys are unique and stable!!
  13. Always bind event handler functions before render! class MyComponent extends

    Component { handleClick(e) { // function content } render() { // Binding in render creates a brand new function // on every update, triggering a prop change. return <Button onClick={() => this.handleClick()} /> } } class MyComponent extends Component { // Bind before render only creates function once // when instance of class is created. handleClick = (e) => { // function content } render() { return <Button onClick={this.handleClick} /> } } ✘ ✔
  14. Never Mutate Objects! Your immutable friends include: • The spread

    operator • Object.assign() • The array functions such as map() and filter(). Don’t use push() and pop()!! • Immutable.js http://redux.js.org/docs/faq/ImmutableData.html#benefits-of-immutability http://reactkungfu.com/2015/08/pros-and-cons-of-using-immutability-with-react-js/ Further reading:
  15. What things do I only do if DevTools show performance

    issues?
  16. Avoid reconciliation when unnecessary. Use shouldComponentUpdate and/or PureComponent

  17. shouldComponentUpdate() class CounterButton extends React.Component { constructor(props) { super(props); this.state

    = {count: 1}; } // If the color prop or the count in state do not change, then return false to avoid reconciliation shouldComponentUpdate(nextProps, nextState) { if (this.props.color !== nextProps.color) { return true; } if (this.state.count !== nextState.count) { return true; } return false; } render() { return ( <button color={this.props.color} onClick={() => this.setState(state => ({count: state.count + 1}))}> Count: {this.state.count} </button> ); } } Warning: If `false`, none of the child nodes will be checked either!
  18. PureComponent // Inheriting from PureComponent so all props and items

    in state will be shallow compared before updating class CounterButton extends React.PureComponent { constructor(props) { super(props); this.state = {count: 1}; } render() { return ( <button color={this.props.color} onClick={() => this.setState(state => ({count: state.count + 1}))}> Count: {this.state.count} </button> ); } } Warnings: 1. Complex mutated states won’t trigger an update. Don’t mutate! 2. All subcomponents must be pure as well.
  19. Never Mutate Data! Your immutable friends include: • The spread

    operator • Object.assign() • The array functions such as map() and filter(). Don’t use push() and pop()!! • Immutable.js http://redux.js.org/docs/faq/ImmutableData.html#benefits-of-immutability http://reactkungfu.com/2015/08/pros-and-cons-of-using-immutability-with-react-js/ Further reading:
  20. Memoize any computed props in Redux mapStateToProps() Use the Reselect

    package
  21. // Computed values passed into `connect()` // return a new

    object every time // Helper function for filtering things const getVisibleThings = (things, filter) => { switch (filter) { case 'SHOW_ALL': return things case 'SHOW_OPEN': return things.filter(things => things.open) case 'SHOW_CLOSED': return things.filter(things => !things.open) default: return things } } const mapStateToProps = (state) => { return { things: getVisibleThings(state.things, state.filter) } } connect(mapStateToProps)(SomeComponent) import {createSelector} from 'reselect' // Selector functions for non-computed properties const getThings = (state) => state.things const getFilter = (state) => state.filter // Create memoized selector function to return // computed object only if the inputs change const selectComputedData = createSelector( [getThings, getFilter], (things, filter) => { switch (filter) { case 'SHOW_ALL': return things case 'SHOW_OPEN': return things.filter(things => things.open) case 'SHOW_CLOSED': return things.filter(things => !things.open) default: return things } } ) const mapStateToProps = (state) => { return { things: selectComputedData(state) } } connect(mapStateToProps)(SomeComponent) ✘ ✔
  22. Ugh… how do I find my problems?

  23. Use Perf to profile your app! $ npm install react-addons-perf

    --save-dev
  24. Perf in action Steal my widget from https://github.com/siakaramalegos/react_perf_widget

  25. What if I need MOAR SPEED?

  26. Learn about: Server-Side Rendering (SSR) Code Splitting with Webpack Progressive

    Web Apps (PWAs)
  27. Summary • Use the production version of React in production

    • Use unique, stable keys in arrays and iterators • Bind event handler functions before render • Never mutate data Performance is important because both load time and responsiveness impact user experience. Alwaysdo: Only do if have problems: • Avoid reconciliation when unnecessary ◦ shouldComponentUpdate() ◦ PureComponent • Memoize computed props in Redux using Reselect
  28. Resources you should totally check out…* Chrome DevTools Real time

    performance audit with Chrome DevTools, lecture and demo by Jon Kuperman Chrome DevTools docs by Google Analyzing Network Performance by Kayce Basques at Google Analyzing Runtime Performance by Kayce Basques at Google React + Redux Performance Optimizing Performance, Reconciliation, Performance Tools, PureComponent official docs by Facebook Never Bind in Render by Ryan Funduk Don't Use Bind When Passing Props by Dave Ceddia 9 things every React.js beginner should know by Cam Jackson - opinionated but some great tips Optimizing the Performance of Your React Application by Alex Sears, includes a tutorial How to Benchmark React Components: The Quick and Dirty Guide by Scott Domes Performance Engineering With React and A Deep Dive Into React Perf Debugging by Saif Hakim Reselect npm package, by the React Community React/Redux Performance Tuning Tips by Arik Maor * Don’t read this slide. It’s here for when you look at these slides later.
  29. Thanks! thegreengreek on Twitter and Medium siakaramalegos on GitHub Slides:

    https://tinyurl.com/lightningreactconnect Give me feedback: https://tinyurl.com/siaspeaks