While React's speed is usually pretty good, it's quite common to find areas of your app which are slow, or which stutter when you try to input data or scroll. The cause of these slowdowns is usually unecessary work or re-renders performed by React - for instance, re-rendering a component also causes React to check every child component to see if it should re-render, so if you have a list with hundreds of items then this can cause a lot of slowdown.
A good tool to identify which parts of your app are causing problems is the React Performance tool from Facebook. This tool will show you which components in your app are being recalculated unnecessarily, which gives you a good starting point to speeding things up.
Install the tool via NPM:
npm install --save-dev react-addons-perf
then, if you're using Webpack or similar, load the module and add it to the window scope so it can be called from dev tools:
import Perf from 'react-addons-perf';
window.Perf = Perf;
Alternatively, you can use Webpack's loader functionality:
import 'expose?Perf!react-addons-perf'
or
loaders: [
{
test: require.resolve("react-addons-perf"),
loader: "expose?Perf"
}
]
Note: I haven't used the expose loader, so I can't comment on how well it works (or how easy it is to set up).
Open the browser's dev tools, and find the area of the app you want to profile. In the dev tools console, start the performance profiler - Perf.start()
- then perform the actions in the app which are slow. Stop the tools via Perf.stop()
, and then print the results via Perf.printWasted()
. This will show you components in the app which are recalculated but then not re-rendered (e.g. a parent component may have changed which causes React to check whether the child components should re-render, but nothing in the child component has changed so React doesn't end up re-rendering).
The components highlighted by printWasted
are simple enough to optimise - usually, just updating the shouldComponentUpdate
method to check if the props or state have changed is enough to prevent multiple recalculations:
import _ from 'lodash';
shouldComponentUpdate (nextProps, nextState) {
return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
}
There are also a lot of good performance tips in these articles, including splitting components into multiple sub-components to prevent re-rendering, and why bind()
should be avoided in JSX syntax.