Forward Advance Learning

Optimising Compilation with Pure Components

When we render a react app, by default we traverse the entire component tree. This is typically fine because traversing the tree is typically orders of magnitude faster than updating the DOM, and React already optimised DOM updates (see section 1).

However, this isn't always the case. Say we have a component that deals with some large data structure, it might not be OK to traverse that structure on each user interaction.

For This, we have shouldComponentUpdate

React gives us a callback shouldComponentUpdate(newProps, newState). This callback has one job, to return true or false. If it returns true, the component will render, and traversal will continue down the tree. If it returns false, render will not be called, and the subtree will not be updated.

The default shouldComponentUpdate simply returns true, meaning that the component will always update, but we can override this:

class CatList extends React.Component {
shouldComponentUpdate(newProps) {
return this.props.cats != newProps.cats
}
}

The CatList will only rerender if the cats actualy change.

Immutables

To make this work, we need to use immutables. If we just push to the array each time, we the props test will always fail.

Here we add a new cat to the list:

newCats = [...cats, "Miffy"]

PureComponent - There's a Subclass for That

Rather than just overriding shouldComponentUpdate all over the place, we can extend React.PureComponent

class CatList extends React.PureComponent {
render() {/* Code goes here */}
}

This gives a default shouldComponentUpdate that returns true if the state or props have changed since the last render.

PureComponent in Action

Here's an example of how PureComponent can help us. This example renders a list of 100,000 items, and also lets you set a name for a cat. Slightly contrived I know, but hopefully sufficient to get the point across.

Typing in the CatForm sets the state on the App, which in turn will rerender the TodoContainer.

Depending on your CPU, this will lock up your browser for a few seconds or more

We can't do much about the initial render, but we can certainly make the compiled app faster, by having TodoContainer inherit from React.PureComponent.

See the Pen React PureComponent Demo by Nicholas Johnson (@superluminary) on CodePen.

Make TodoListContainer extend React.PureComponent and check the performance.
Bonus: Make a Todo component that renders a single Todo. Make a method that edits a single todo in App state.todos. Remember to make state.todos immutable. Now make Todo a pure component and see the speed improvement. We can skip rendering most of the list, and only render a single item in it.

When do I Use This?

This will depend on you. Some people make every single component a PureComponent. This sounds fast, but actually adds overhead for simple presentational components that can be more effectively rendered as a function.

Remember that React already optimises DOM updates for you, and calling a simple function that renders a few divs is blazingly fast already.

So how to know which parts of your app are slow?

Performance Profiling

Luckily, create-react-app comes with support for performance profiling.

Visit http://localhost:3000?react_perf

Now in Chrome developer tools, navigate to the performance tab, and click record. Navigate around your app for a while, then click stop.

You'll see a visualisation of where the browser spent its time. In amongst all the DOM stuff, there will be a section marked User Timing. This contains a full breakdown of all your components.