The useMemo Hook in React returns a value that has been memoized.
Consider memoization as caching a value to avoid recalculating it. |
The useMemo Hook in React returns a cached value that is only recalculated when its dependencies change.
The useMemo and useCallback Hooks are similar, with the primary difference being that useMemo returns a memoized value, while useCallback returns a memoized function. For more details on useCallback, refer to its dedicated chapter.
|
Performance
The useMemo
Hook helps prevent costly, resource-intensive functions from running unnecessarily.
In this example, an expensive function executes on every render, causing noticeable delays when changing the count or adding a todo.
Example:
A poorly performing function, expensiveCalculation, runs on every render.
import { useState } from "react";
import ReactDOM from "react-dom/client";
const App = () => {
const [count , setCount ] = useState(0);
const [todos , setTodos ] = useState([]);
const calculation = expensiveCalculation(count );
const increment = () => {
setCount((c) => c + 1);
};
const addTodo = () => {
setTodos((t) => [...t , "New Todo"]);
};
return (
<div <div> <h2>My Todos</h2> {todos .map((todo, index) => {
return <p key={index}>{todo }</p>;
})} <button onClick={addTodo}>Add Todo</button> </div> <hr /> <div> Count: {count } <button onClick={increment}>+</button> <h2>Expensive Calculation</h2> {calculation } </div> </div>
); ;
const expensiveCalculation = (num) => {
console .log("Calculating...");
for (let i = 0; i < 1000000000; i ++) {
num += 1;
}
return num ; };
const root = ReactDOM .createRoot(document .getElementById('root'));
root .render(<App />);
|
Use useMemo
To address this performance issue, use the useMemo Hook to memoize the expensiveCalculation function, ensuring it runs only when necessary.
Wrap the expensive function call with useMemo, and specify dependencies as the second parameter. The function will execute only when its dependencies change. In the example below, the expensive function runs only when the count changes, not when todos are added.
Example:
Performance example demonstrating the use of the useMemo Hook:
import { useState , useMemo } from "react";
import ReactDOM from "react-dom/client";
const App = () => {
const [count , setCount ] = useState(0);
const [todos , setTodos ] = useState([]);
const calculation = useMemo(() => expensiveCalculation(count ), [count ]);
const increment = () => {
setCount((c) => c + 1);
};
const addTodo = () => {
setTodos((t) => [...t , "New Todo"]);
};
return (
<div> <div> <h2>My Todos</h2> {todos .map((todo, index) => {
return <p key={index}>{todo }</p>;
})} <button onClick={addTodo}>Add Todo</button> </div> <hr /> <div> Count: {count } <button onClick={increment}>+</button> <h2>Expensive Calculation</h2> {calculation } </div> </div>
); };
const expensiveCalculation = (num) => {
console .log("Calculating...");
for (let i = 0; i < 1000000000; i ++) {
num += 1;
}
return num ; };
const root = ReactDOM .createRoot(document .getElementById('root'));
root .render(<App />);
|