Skip to content

Pure Components

In the last lesson, we saw how a component will automatically re-render when its parent re-renders, regardless of whether or not its props have changed.

In larger applications, this can lead to performance problems. A single state change might re-render dozens or even hundreds of components, even if only a small fraction of them actually need to re-render.

Fortunately, React provides an escape hatch we can use: the React.memo utility.

Here's what it looks like:

function Decoration() {
return (
<div className="decoration">
⛵️
</div>
);
}
const PureDecoration = React.memo(Decoration);
export default PureDecoration;

React.memo is a utility that lets us tell React: “Hey, this component is pure! It doesn't need to re-render unless its props or state changes. It will always return the exact same UI when given the same props + state”.

It takes a component as an argument (Decoration) and augments it, giving it a new super-power: it can selectively ignore re-renders that don't affect it.

When the parent component re-renders, React will try to re-render the child PureDecoration, but PureDecoration steps in and says “None of my props have changed, and so I won't be re-rendering this time.”

This uses a technique known as memoization.

It's missing the R, but we can sorta think of it as “memorization”. The idea is that React will remember the previous snapshot. If none of the props have changed, React will re-use that stale snapshot rather than going through the trouble of generating a brand new one.

Let's suppose I wrap both BigCountNumber and Decoration with the React.memo helper. Here's how this would affect the renders:

App

Counter

count: 0

BigCountNumber

Props: { count }

Pure Component

Decoration

Pure Component

When count changes, we re-render Counter, and React will try to render both descendant components.

Because BigCountNumber takes count as a prop, and because that prop has changed, BigCountNumber is re-rendered. But because Decoration's props haven't changed (on account of it not having any), the original snapshot is used instead.

I like to pretend that React.memo is a bit like a lazy photographer. If you ask it to take 5 photos of the exact same thing, it'll take 1 photo and give you 5 copies of it. The photographer will only snap a new picture when your instructions change.

Here's a live-code version, if you'd like to poke at it yourself. Each memoized component has a console.info call added, so you can see in the console exactly when each component renders:

Code Playground

import React from 'react';

function Decoration() {
console.info('Decoration render');
return (
<div className="decoration">
⛵️
</div>
);
}

export default React.memo(Decoration);
preview
console
  1. BigCountNumber render
  2. Decoration render

To summarize:

  • The only way to re-render anything in React is to update a state variable by calling a state-setter function (eg. setCount).
  • When a component re-renders, it automatically re-renders all of its descendants, even if none of their props have changed.
  • We can wrap our component with React.memo to optimize it, so that it only re-renders if at least 1 of its props have changed since the last render.