20
loading...
This website collects cookies to deliver better user experience
React.memo()
is one of those things that should be a part of every React developer's arsenal. It gives us the ability to memoize a React component. As with any tool, before we delve into how to use React.memo()
, let's understand the problem first.An important point to remember is that whenever memoization is used, there must be a criteria which would dictate when the cached results are no longer valid and the computation must be done again.
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;
<App />
. To keep it simple, we'll create a <Message />
component that returns some kind of message depending on the msgId
that is passed to it as a prop.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>;
}
<Message />
component does some heavy computation or perhaps sends a request to an external API in order to get the final message. We'll simulate this situation by adding everyone's favorite console.log()
in 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>;
}
<App />
component 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;
count
is changed, the heavy computation is done.To understand why the heavy computation is done every time count
changes, check out this post: Re-rendering in React
count
does not affect <Message />
in any way but still every time count
is updated, the seriously heavy computation is performed. We only want the computation to occur if the msgId
changes because a change in msgId
should result in a different message.React.memo()
is a higher-order component. It accepts a component as its argument and memoizes the result. The memoized result is updated only if the props of the original component are changed.React.memo()
, simply pass your component as an argument and save the result. Our <Message />
component will become: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've only imported memo()
here. If you have React
imported, you can use React.memo()
instead of just memo()
.
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;
count
no longer has that result.