React / Memoization with React.memo
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.