All posts

React / Memoization with React.memo

Posted On 03.28.2022

Memoization is the technique to let an expensive function return the cached value if all of its arguments remain unchanged.

When a React component is wrapped inside a React.memo, the render result of that component will be memoized. If you pass the same props, React will skip re-rendering that component.

Let’s take a look at this example: We create a component Book that takes a string as title. And an “Update” button.

const BookComponent = ({ title }) => {
    console.log("Render book with ", title);
    return <div>{title}</div>;
};
const Book = BookComponent;
 
const DemoApp = () => {
    const [title, setTitle] = React.useState("Hello, World!");
    const update = () => {
        setTitle("Hello, World!");
    };
    return (
    <div>
        <Book title={title} />
        <button onClick={update}>Update</button>
    </div>
    );
};

Every time you click the “Update” button, we update the title state, the Book component will always be re-rendered, even if the title value remains the same.

To keep the Book component from being re-rendered, we can wrap it with React.memo:

const Book = React.memo(BookComponent);

Now, when updating the state, the BookComponent will be called, but the input props have been memoized before, so React will skip rendering.

By default, React.memo only do a shallow comparison on the props, this means, if the input prop is an object, the memoization will be broken.

For example, instead of taking a title string, we change the BookComponent to take an object instead:

const BookComponent = ({ book: { title } }) => {
    console.log("Render book with ", book.title);
    return <div>{book.title}</div>;
};
const Book = React.memo(BookComponent);
 
const DemoApp = () => {
    const [data, setData] = React.useState({
        book: {
            title: "Hello, World!"
        }
    });
    const update = () => {
        setData({
            book: {
                title: "Hello, World!"
            }
        });
    };
    return (
    <div>
        <Book data={book} />
        <button onClick={update}>Update</button>
    </div>
    );
};

Clicking “Update” will always result in a re-render. In this case, we can provide React.memo a custom comparison function:

const compare = (prevProps, currentProps) => {
    return prevProps.book.title === currentProps.book.title;
};
 
const Book = React.memo(BookComponent, compare);

Now, memoization will work again.

It’s a best practice to only use React.memo on complex components or components that do not require an update when props change.