The useMemo
Hook in React returns a memoized value. Think of memoization as caching a value to avoid recalculating it. The useMemo
Hook only re-executes when one of its dependencies changes, which can boost performance.
The useMemo
and useCallback
Hooks are similar. The key difference is that useMemo
returns a memoized value, while useCallback
returns a memoized function.
Performance
The useMemo
Hook is useful for preventing expensive, resource-intensive functions from running unnecessarily.
Consider this example where an expensive function runs on every render. When changing the count or adding a task, you’ll notice a delay in execution.
Example
A poorly performing function. The costlyComputation
function runs on every render
import { useState } from "react"; import ReactDOM from "react-dom/client"; const App = () => { const [count, setCount] = useState(0); const [tasks, setTasks] = useState([]); const calculation = costlyComputation(count); const increment = () => { setCount((c) => c + 1); }; const addTask = () => { setTasks((t) => [...t, "New Task"]); }; return ( <div> <div> <h2>My Tasks</h2> {tasks.map((task, index) => { return <p key={index}>{task}</p>; })} <button onClick={addTask}>Add Task</button> </div> <hr /> <div> Count: {count} <button onClick={increment}>+</button> <h2>Costly Calculation</h2> {calculation} </div> </div> ); }; const costlyComputation = (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 resolve this performance issue, use the useMemo
Hook to memoize the costlyComputation
function. This ensures the function only runs when necessary.
Wrap the expensive function call with useMemo
. The useMemo
Hook accepts a second parameter for declaring dependencies. The expensive function will only re-execute when its dependencies change.
In the following example, the expensive function runs only when count
changes and not when tasks are added.
Example
Performance example using the useMemo
Hook, by using useMemo
, the TaskList
component will only re-render when the tasks
prop changes.
import { useState, useMemo } from "react"; import ReactDOM from "react-dom/client"; const App = () => { const [count, setCount] = useState(0); const [tasks, setTasks] = useState([]); const calculation = useMemo(() => costlyComputation(count), [count]); const increment = () => { setCount((c) => c + 1); }; const addTask = () => { setTasks((t) => [...t, "New Task"]); }; return ( <div> <div> <h2>My Tasks</h2> {tasks.map((task, index) => { return <p key={index}>{task}</p>; })} <button onClick={addTask}>Add Task</button> </div> <hr /> <div> Count: {count} <button onClick={increment}>+</button> <h2>Costly Calculation</h2> {calculation} </div> </div> ); }; const costlyComputation = (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 />);