Improving Performance in React and Redux Applications - Some Quick Wins

 

Intro
Martin McKeaveney

Software Engineer @

The bottleneck

When a component calls `this.setState()`, React re-renders the DOM in two stages:
  1. React’s internal Virtual DOM is re-rendered
  2. The diff between the previous virtual DOM and current DOM is calculated and changes are applied to the actual DOM
If the first step takes too long, re-rendering will be slow.

 

 

Quick Win One - Avoid Unnecessary Re-renders
This is the core principle of pretty much all React performance optimisations.

 

 

 

 

 


  • Allows you to specify if a component renders based on the boolean returned.
  • Default implementation always returns true.
  • Pure components use shallow compare and shouldComponentUpdate.
  • Be careful with this!
  • as of React 15.3, React.PureComponent is a new base class that replaces the need to use Shallow Compare plugin or the Pure Render mixin.

 

 

ShouldComponentUpdate & Pure Components
Higher Order Components
  • We can use HOCs to implement the previous optimisations
  • HoCs are functions that accept a base component and return a new component with additional functionality
  • Cleaner syntax
  • Nice utilities with Recompose

 

Quick Win Two - Redux and connect()

  • connect() is a HOC
  • Takes the redux store as context
  • The connected component is only rendered when the relevant values are changed (shallow compare) - BUT
  • BUT - 

Enter Selectors
  • Works like a cache (think memoize in lodash) 
  • Selectors can compute derived data
  • Only recompute when one of their argument functions returns a different value.
  • If changed the transform function is then called, otherwise return the previously computed value.
  • Act as composable functions that can be used in other selectors
Quick Win 3 - The Pure Render Antipattern
  • tl;dr. The anti-pattern is creating new arrays, objects, functions or any other new identities during render or in Redux connect(mapState).
  • In Javascript, different instances have different identities.
  • Shallow equality will produce false and tells React to re-render the components.
  • ie. [] is equivalent to new Array();

 

The Pure Render Antipattern (cont.)
Functions

 

 

 

 

 

 

Arrays
The Pure Render Antipattern (cont.)

We can also avoid binding inside the component by binding in an higher-order component like recompose.withHandlers() or redux.connect()

 

 

 

 

 

 

  • Timeline/Performance tab in Chrome DevTools
  • Records time executing code and time rendering
  • React Render included in code execution time
  • The actual DOM render is included in the rendering part of the timeline
  • You can also make use of the Redux Devtools slider to time your actions and record them.
  • Look for long total times and short self-times. This usually means a React component issue.

 

 

Debugging/Profiling

Chrome DevTools Profiler

Debugging/Profiling

React Perf

To Summarise/Other Tweaks
  • Only optimise when you really need to
  • Keep render() slim (Think functional)
  • Keep comparisons shallow (Immutability)
  • Build for production and use all the plugins - Uglify, define etc.
  • Stateless (functional) components are not any faster than the pure Stateful class (Right Now)
  • Normalise your state, prefer objects by ID as opposed to large nested arrays - O(1)  as opposed to O(n).
  • Rendering in React 15 is roughly 25% faster compared to 0.14
  • Pure components are the fastest. Use shouldComponentUpdate
  • Rendering in development mode is 2–8x slower than rendering in production
  • Rendering in development with React 15 is about 2x slower than 0.14

 

Thanks!

 

Questions? 

 

Links

https://github.com/acdlite/recompose


https://github.com/reactjs/reselect

 

https://facebook.github.io/react/docs/perf.html

 

 

Improving Performance In React/Redux Applications

By Martin McKeaveney

Improving Performance In React/Redux Applications

  • 782