Lightning Fast React - Agent Conf

6e0ba5b45dafe063b98db2a1d5391433?s=47 Sia
January 19, 2018

Lightning Fast React - Agent Conf

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.



January 19, 2018


  1. LIGHTNING Fast React Sia Karamalegos @thegreengreek

  2. @thegreengreek Who Am I? @thegreengreek siakaramalegos @thegreengreek nolasia (not code)

  3. @thegreengreek What are we going to talk about? 1. Why

    you should care about UX performance 2. Things you should always do 3. Things you should do only if you your app is too slow 4. Big picture UX performance, a.k.a. the 80-20 rule
  4. @thegreengreek "53% of mobile site visits are abandoned if pages

    take longer than 3 seconds to load" DoubleClick by Google, 2016
  5. @thegreengreek What about responsiveness?

  6. @thegreengreek What are we trying to make FASTER? Load Re-render

  7. @thegreengreek What things should I always do?

  8. @thegreengreek Always use the production version of React in production!

    Or… Don’t ignore the warnings!
  9. @thegreengreek 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
  10. @thegreengreek Declare the correct NODE_ENV in Webpack new webpack.DefinePlugin({ 'process.env':

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

    the warnings!
  12. @thegreengreek <!-- 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>Turtle</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> <!– Adding item only inserts new Kangaroo item. Way more efficient! --> <ul> <li key="turtle">Turtle</li> <li key="sloth">Sloth</li> <li key="lemur">Lemur</li> <li key="koala">Koala</li> </ul> ✘ ✔
  13. @thegreengreek <!-- Scenario 3: Useless keys. Boo. --> <ul> <li

    key="1">Sloth</li> <li key="2">Lemur</li> <li key="3">Koala</li> </ul> <!– Adding item re-renders entire list because item with key of 1 is different before & after, for every item. Don't accidentally do this with! --> <ul> <li key="1">Turtle</li> <li key="2">Sloth</li> <li key="3">Lemur</li> <li key="4">Koala</li> </ul> ✘ Make sure keys are unique and stable!!
  14. @thegreengreek 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} /> } } ✘ ✔
  15. @thegreengreek 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 Further reading:
  16. @thegreengreek What things do I only do if DevTools show

    performance issues?
  17. @thegreengreek Avoid reconciliation when unnecessary. Use shouldComponentUpdate and/or PureComponent

  18. @thegreengreek 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!
  19. @thegreengreek 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.
  20. @thegreengreek Memoize any computed props in Redux mapStateToProps() Use the

    Reselect package
  21. @thegreengreek // 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 => case 'SHOW_CLOSED': return things.filter(things => ! 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 => case 'SHOW_CLOSED': return things.filter(things => ! default: return things } } ) const mapStateToProps = (state) => { return { things: selectComputedData(state) } } connect(mapStateToProps)(SomeComponent) ✘ ✔
  22. @thegreengreek Virtualize Long Lists Use “windowing” to only render a

    subset of items at one time, cutting down on both render and re-render time. React Virtualized is one tool you can use.
  23. @thegreengreek Big picture: what really matters?

  24. @thegreengreek The Pareto Principle: Roughly 80% of the effects come

    from 20% of the causes
  25. @thegreengreek Be lazy. Don’t optimize what you don’t need to.

  26. @thegreengreek How does this make you feel?

  27. @thegreengreek

  28. @thegreengreek Learn browser Dev Tools already If this gives you

    anxiety, you need to learn profiling with dev tools better.
  29. @thegreengreek Use React Dev Tools

  30. @thegreengreek Analyze your Webpack Bundles

  31. @thegreengreek Images “ account for 60% of the bytes on

    average needed to load a webpage.” Google,
  32. @thegreengreek If you need MOAR speed, learn about: Tree shaking

    Code splitting Server-Side Rendering (SSR) Progressive Enhancement
  33. @thegreengreek Resources you should totally check out…* DevTools, Webpack, Images

    Debugging React performance with React 16 and Chrome Devtools by Ben Schwarz Real time performance audit with Chrome DevTools, lecture and demo by Jon Kuperman Chrome DevTools docs by Google Analyzing Network Performance and Analyzing Runtime Performance by Kayce Basques at Google Build Analysis on SurviveJS by Juho Vepsäläinen High-performance webpack config for front-end delivery by Drew Powers Responsive Images by Pete LePage at Google Responsive images free course by Google & Udacity Loading images (webpack) SurviveJS by Juho Vepsäläinen React + Redux Performance Optimizing Performance official docs by Facebook Debugging React performance with React 16 and Chrome Devtools by Ben Schwarz 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 Pros and Cons of using immutability with React.js by Marcin Grzywaczewski What are the benefits of immutability? from Redux docs 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.
  34. @thegreengreek Thanks! thegreengreek on Twitter and Medium siakaramalegos on GitHub

    Slides & Resources: Give me feedback: