React useMemo Hook

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 />);

Scroll to Top