React.memo()
is one of those things that should be part of every React developer's arsenal. It gives us the ability to remember the React component. As with any tool, before we dive into how to use React.memo()
, let's first deal with the problem.
Why do you need memoization?
Memoization is a general concept that basically means caching the results of some computation for later use. This is an optimization technique that is quite widely used in the programming world.
It is important to remember that whenever memoization is used, there must be a criterion that will determine when the cached results are no longer valid and the computation must be performed again.
To understand the problem it solves, consider the following React component:
import { useState, Fragment } from "react";
function App() {
const [count, setCount] = useState(0);
function handleDecrement() {
setCount((oldCount) => --oldCount);
}
function handleIncrement() {
setCount((oldCount) => ++oldCount);
}
return (
<Fragment>
<p>Count is {count}</p>
<button onClick={handleDecrement}>-</button>
<button onClick={handleIncrement}>+</button>
</Fragment>
);
}
export default App;
A simple component that keeps track of which can be increased or decreased.
Now let's add another component to <App />
. To make things easier, we will create a component <Message />
that returns some kind of message depending on the ID msgIdpassed to it as props.
function Message(props) {
let msg = "hello, world";
if (props.msgId === 1) {
msg = "hey there!";
} else if (props.msgId === 2) {
msg = "hola!";
}
return <p>{msg}</p>;
}
We've kept it simple here, but imagine this component <Message />
doing some heavy computation, or perhaps sending a request to an external API to get the final message. We will simulate this situation by adding console.log()
all the favorites to the mix.
function Message(props) {
let msg = "hello, world";
console.log("Just performed some seriously heavy computation");
if (props.msgId === 1) {
msg = "hey there!";
} else if (props.msgId === 2) {
msg = "hola!";
}
return <p>{msg}</p>;
}
Let's update the component <App />
to use <Message />
.
import { useState, Fragment } from "react";
function Message(props) {
let msg = "hello, world";
console.log("Just performed some seriously heavy computation");
if (props.msgId === 1) {
msg = "hey there!";
} else if (props.msgId === 2) {
msg = "hola!";
}
return <p>{msg}</p>;
}
function App() {
const [count, setCount] = useState(0);
function handleDecrement() {
setCount((oldCount) => --oldCount);
}
function handleIncrement() {
setCount((oldCount) => ++oldCount);
}
return (
<Fragment>
<Message msgId={1} />
<p>Count is {count}</p>
<button onClick={handleDecrement}>-</button>
<button onClick={handleIncrement}>+</button>
</Fragment>
);
}
export default App;
In the video below, pay particular attention to the fact that with every change count , heavy calculations are performed.
At this point, take a step back and consider how ineffective our user interface is at the moment. count
does not affect in any way <Message />
, but still count
very heavy computation is performed every time you update . We only want the computation to happen on change msgId
, because the change msgId
should result in a different message.
React.memo () rushes to the rescue
React.memo()
higher order component. It takes a component as an argument and remembers the result. The memoized result is updated only if the properties of the original component change.
To use React.memo()
, just pass your component as an argument and store the result. Our component <Message />
will be:
import { useState, Fragment, memo } from "react";
const Message = memo(function (props) {
let msg = "hello, world";
console.log("Just performed some seriously heavy computation");
if (props.msgId === 1) {
msg = "hey there!";
} else if (props.msgId === 2) {
msg = "hola!";
}
return <p>{msg}</p>;
});
Note: I just imported here memo()
. If you imported React
, you can use React.memo()
simply instead memo()
.
Our code now looks like this:
import { useState, Fragment, memo } from "react";
const Message = memo(function (props) {
let msg = "hello, world";
console.log("Just performed some seriously heavy computation");
if (props.msgId === 1) {
msg = "hey there!";
} else if (props.msgId === 2) {
msg = "hola!";
}
return <p>{msg}</p>;
});
function App() {
const [count, setCount] = useState(0);
function handleDecrement() {
setCount((oldCount) => --oldCount);
}
function handleIncrement() {
setCount((oldCount) => ++oldCount);
}
return (
<Fragment>
<Message msgId={1} />
<p>Count is {count}</p>
<button onClick={handleDecrement}>-</button>
<button onClick={handleIncrement}>+</button>
</Fragment>
);
}
export default App;
Notice this time that the computation is done when the application is updated, but the change count
no longer has this effect.
Top comments (0)