React is famous for its performance. Because it has a virtual DOM layer and updates the real DOM only when needed. This is much faster than updating the DOM directly all the time, even with the same information. However, React intelligence only goes so far (for now), and our task is to know the expected behavior and limits of React so we don’t accidentally lose performance.

One area of concern is how React decides when to rerender components. Instead of re-rendering the DOM node, you just call the Render method to change the virtual DOM. We can help React by telling React when to render and when not to render. Let’s take a look at each of these in turn.

1. The component status changes

Rerendering of the component is initiated only when the state of the component changes. State changes can be made by props changes, or directly through the setState method. The component gets the new state and React decides if the component should be rerendered. Unfortunately, React unbelievably simply designs the default behavior to be re-rendered every time.

Component changes? Re-render. Parent component changes? Re-render. Part of the props that didn’t cause the view to change? Re-render.

class Todo extends React.Component {

    componentDidMount() {
        setInterval(() => {
            this.setState(() => {
                console.log('setting state');
                return { unseen: "does not display" }
            });
        }, 1000);
    }

    render() {
        console.log('render called');
        return (<div>...</div>);
    }
}Copy the code

In this (very deliberate) example, Todo will re-render every second, even if the Render method isn’t used unseen at all. In fact, the unseen value doesn’t even change. You can see the actual version of this example in CodePen.

Okay, but re-rendering every time doesn’t help.

I mean, I really appreciate React being careful. It is even worse if the state changes but the component is not rendered correctly. On balance, re-rendering every time is definitely a safe choice.

However, the time cost of re-rendering seems to be very expensive (which is shown dramatically in the example).

Yes, re-rendering when unnecessary is a waste of loop and not a good idea. However, React doesn’t know when it’s safe to skip re-rendering, so React re-renders every time, regardless of whether it’s important or not.

How do we tell React to skip rerendering?

That’s the second point.

2. shouldComponentUpdatemethods

The shouldComponentUpdate method returns true by default, which is what causes each update to be rerendered. But you can override this method to make React smarter if you need to optimize performance. Instead of having React re-render every time, you can tell React when you don’t want to trigger a re-render.

When React is about to render a component it executes the shouldComponentUpdate method to see if it returns true (the component should be updated, i.e., re-rendered). So you need to override the shouldComponentUpdate method to return true or false depending on the situation to tell React when to re-render and when to skip re-render.

When you use shouldComponentUpdate you need to consider what data is important for rerendering. Let’s go back to this example.

As you can see, we only want to re-render Todo when the title and done properties change. We don’t care if the Unseen changes, so I didn’t include it in the shouldComponentUpdate method.

When React renders a Todo component (triggered by setState) it first checks to see if the state has changed (via props and state). If the state changes (which happens because we explicitly called setState) React checks Todo’s shouldComponentUpdate method. React determines where to render based on whether the shouldComponentUpdate method returns true or false.

The updated code will still call setState once a second but render will only be called when it is first loaded (or after the title or done attribute has changed). You can see it here.

Looks like a lot of work to do.

Yes, this example is verbose because there are two properties (title and done) to focus on and only one (unseen) to ignore. Depending on your data it might make more sense to just check one or two attributes and ignore the others.

Important note

Returning false does not prevent child components from rerendering when their state changes.Copy the code

— The Facebook React document

This works on the state of the child components, not their props. So if a child component manages some of its own state internally (using its own setState), this will still be updated. But if the parent component’s shouldComponentUpdate method returns false, it will not pass the updated props to its children, so the children will not re-render even if their props change.

Bonus: Simple performance tests

The time to write and run the computation in shouldComponentUpdate can be expensive, so you need to make sure it’s worth it. You can test how long a React cycle takes by default before writing the shouldComponentUpdate method. Armed with this information, you can make a non-blind decision when making performance optimizations.

Use React’s performance tool to find wasted cycles:

Perf.start()
// Do the render
Perf.stop()
Perf.printWasted()Copy the code

Which component is wasting a lot of render cycles? How do you make them smarter with shouldComponentUpdate? Try using a performance testing tool to compare their performance.