Quiz

What is the `useMemo` hook in React and when should it be used?

Topics
React

TL;DR

useMemo caches a calculation result between renders while its dependencies remain Object.is-equal. Use it as a performance optimization for a measured expensive calculation or when a stable object/array identity enables another optimization. It is not a semantic guarantee, so code must remain correct if React discards the cache and recomputes the value. React Compiler can provide equivalent memoization for compatible code when the optional build-time optimizer is enabled.

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

What is the useMemo hook in React and when should it be used?

useMemo caches a calculation result as a performance optimization while its reactive dependencies remain equal.

What is useMemo?

The useMemo hook caches the result of a calculation between renders. React returns the cached value while every dependency remains Object.is-equal, unless it discards the cache for a documented reason. Its purpose is performance optimization, not correctness.

Syntax

The syntax for useMemo is as follows:

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
  • The first argument is a function that returns the value you want to memoize.
  • The second argument is an array of dependencies. React normally reuses the value until a dependency changes, but it may discard the cache for documented reasons.

When should it be used?

Use it when profiling identifies meaningful calculation work or when stable value identity enables another measured optimization.

Expensive calculations

For a measured expensive calculation, useMemo can reuse the previous result while its dependencies remain equal. Candidate work includes filtering or sorting a large list, parsing a large payload, or running a heavy synchronous algorithm—not trivial arithmetic.

import { useMemo } from 'react';
const filterAndSortLargeList = (items, query) => {
// Genuinely expensive: scans every item and sorts the result.
return items
.filter((item) => item.name.toLowerCase().includes(query.toLowerCase()))
.toSorted((a, b) => a.name.localeCompare(b.name));
};
const MyComponent = ({ items, query }) => {
const visibleItems = useMemo(
() => filterAndSortLargeList(items, query),
[items, query],
);
return <List items={visibleItems} />;
};

Preserving referential equality for memoized children

This is the most common practical reason to reach for useMemo. Every render produces a new object/array literal, which breaks React.memo (or useEffect dependency) bailouts on a child. Memoizing the value keeps its reference stable across renders.

import { memo, useMemo } from 'react';
const Parent = ({ items }) => {
// Without useMemo, `sortedItems` would be a new array on every render,
// and `MemoChild` would re-render even when `items` is unchanged.
const sortedItems = useMemo(
() => items.toSorted((a, b) => a.name.localeCompare(b.name)),
[items],
);
return <MemoChild sortedItems={sortedItems} />;
};
const MemoChild = memo(function MemoChild({ sortedItems }) {
return (
<ul>
{sortedItems.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
});

Note that useMemo on a value alone does not prevent the child from re-rendering — the child must also be wrapped in memo (or otherwise short-circuit). items.toSorted(...) is used here because Array.prototype.sort mutates in place; mutating a prop would violate React's read-only props contract.

Caveats

Because the cached value is disposable, application correctness cannot depend on the cache being retained:

  • Overuse: Overusing useMemo can lead to more complex code without significant performance benefits. It should be used judiciously.
  • Dependencies: Make sure to correctly specify all dependencies. Missing dependencies can lead to stale values, while extra dependencies can lead to unnecessary recalculations.
  • It is only a cache: React may throw away the value for documented reasons, including editing the component in development or suspending during its initial mount. Never rely on useMemo for correctness.
  • React Compiler changes the calculus: React Compiler 1.0 is a stable, optional build-time optimizer. When enabled, it memoizes compatible components and values, reducing the need for hand-written useMemo and useCallback. Keep explicit memoization when the Compiler is not enabled or when profiling and compiled output show a specific calculation or identity still needs it.

Further reading

Exercises

Check your understanding
Beta
Check your understanding Exercise
Check your understanding Exercise

Which use of useMemo has a defensible purpose?