In this example, both Foo and Bar are re-rendered whenever the isFooVisible value is changed in the state of their parent component App .

In this case, it’s necessary to place the isFooVisibile value in the state of App in order to decide on whether Foo should be rendered. Therefore, we can’t really move that value down in the state of Foo . Yet, it’s absolutely unnecessary to re-render Bar when that value changes, since the render output of Bar is independent of it. We only want to re-render Bar when its prop name changes, since its render output is dependent on it.

How do we solve this? 🤔

One way to solve this is to memoize Bar :

const Bar = React.memo(function Bar({name}) {

return <h1>{name}</h1>;

});

This will make sure not to re-render Bar unless name changes its value!

You can also reach the same solution if the Bar component is a class by extending React.PureComponent instead of React.Component :

class Bar extends React.PureComponent {

render() {

return <h1>{name}</h1>;

}

}

Therefore, one way of avoiding unnecessary render calls of a component A, is to memoize that component by using React.memo if it’s a function or by extending React.PureComponent if it’s a class.

Should every component be a PureComponent or memo?

If the previous tip avoids us unnecessary re-renders, why don’t we just PureComponent for every class component and React.memo for every functional one? Why do we even have React.Component if there is already a better version of it? Why isn’t every functional component memoized by default?

Well, because these solutions are not always ideal.

Problem with nested objects

What do PureComponent and React.memo components do under the hood?

At every update (either state or the component above re-renders), they perform a shallow comparison between the keys and values of the new props and state, and the old ones. The shallow comparison is pretty much a strict equality check. If it detects a difference, a render call is performed:

// expected behavior with primitive values

shallowCompare({ name: 'bar'}, { name: 'bar'}); // output: true

shallowCompare({ name: 'bar'}, { name: 'bar1'}); // output: false

You can learn more about the default shallow function used in PureComponent and React.memo here.

Although this comparison works well for primitive values (such as strings, numbers, and booleans), it can lead to undesired behaviors with more complex values such as objects:

// unexpected behavior with primitive values

shallowCompare({ name: {first: 'John', last: 'Schilling'}, {first: 'John', last: 'Schilling'}); // output: false