Improving Performance in React and Redux Applications - Some Quick Wins
Intro
Martin McKeaveney
Software Engineer @
When a component calls `this.setState()`, React re-renders the DOM in two stages:
React’s internal Virtual DOM is re-rendered
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()
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
Debugging/Profiling
To Summarise/Other Tweaks
https://github.com/acdlite/recompose https://github.com/reactjs/reselect
https://facebook.github.io/react/docs/perf.html