useMemo Hook
Cache the result of an expensive computation between renders.
Search across all documentation pages
Cache the result of an expensive computation between renders.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Quick-reference recipe card - copy-paste ready.
const memoizedValue = useMemo(() => computeExpensive(a, b), [a, b]);
// Memoize a derived array/object to stabilize references
const filtered = useMemo(
() => items.filter((item) => item.active),
[items]
);When to reach for this: You have an expensive calculation that should not re-run on every render, or you need a stable object/array reference for a dependency array or child prop.
"use client";
import { useMemo, useState } from "react";
function fibonacci(n: number): number {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
export function FibonacciCalculator() {
const [num, setNum] = useState(10);
const [theme, setTheme] = useState<"light" | "dark">("light");
const result = useMemo(() => fibonacci(num), [num]);
return (
<div className={theme === "dark" ? "bg-gray-900 text-white p-4" : "bg-white text-black p-4"}>
<label className="flex items-center gap-2">
n =
<input
type="number"
value={num}
onChange={(e) => setNum(Number(e.target.value))}
className="w-20 border rounded px-2 py-1"
max={40}
/>
</label>
<p className="mt-2 font-mono">fibonacci({num}) = {result}</p>
<button
onClick={() => setTheme((t) => (t === "light" ? "dark" : "light"))}
className="mt-2 px-3 py-1 border rounded text-sm"
>
Toggle theme
</button>
</div>
);
}What this demonstrates:
fibonacci calculation is memoized and only recalculates when num changesuseMemo, every re-render (including theme toggle) would re-run the expensive calculationObject.isuseMemo is a performance optimization, not a semantic guarantee - React may discard the cache in some cases (e.g., offscreen components)| Parameter | Type | Description |
|---|---|---|
factory | () => T | Function that computes the value to memoize |
dependencies | unknown[] | Array of reactive values the computation depends on |
| Return | Type | Description |
|---|---|---|
memoizedValue | T | Cached result of the factory function |
Stabilize an object for a dependency array:
const options = useMemo(
() => ({ page, pageSize, sortBy }),
[page, pageSize, sortBy]
);
useEffect(() => {
fetchData(options);
}, [options]);Memoize a filtered/sorted list:
const sortedUsers = useMemo(
() => [...users].sort((a, b) => a.name.localeCompare(b.name)),
[users]
);Memoize a component tree (rare):
const chart = useMemo(
() => <ExpensiveChart data={data} />,
[data]
);// Return type is inferred from the factory
const total = useMemo(() => items.reduce((sum, i) => sum + i.price, 0), [items]);
// total: number
// Explicit generic when inference is too wide
const config = useMemo<Config>(() => ({ retries: 3, timeout: 5000 }), []);Premature optimization - Wrapping every value in useMemo adds complexity without measurable benefit for cheap computations. Fix: Profile first. Only memoize when you can measure a performance problem.
Missing dependencies - Omitting a dependency causes the memoized value to be stale. Fix: Include all reactive values used inside the factory.
Unstable dependency references - If a dependency is a new object/array on every render, useMemo recalculates every time anyway. Fix: Memoize the dependency itself, or restructure to depend on primitives.
Side effects in the factory - useMemo runs during rendering; side effects (fetching, subscriptions) break React's rules. Fix: Move side effects to useEffect or event handlers.
Not a guarantee - React may drop memoized values for offscreen components and recalculate later. Fix: Never rely on useMemo for correctness - only for performance.
| Alternative | Use When | Don't Use When |
|---|---|---|
| No memoization | The computation is cheap (string concatenation, simple math) | Computation is measurably slow |
React.memo | You want to skip re-rendering an entire child component | You need to memoize a value, not a component |
useCallback | You need a stable function reference, not a stable value | You need to cache a non-function value |
useDeferredValue | You want to defer rendering expensive content without blocking input | You need to cache computation results |
| Server-side computation | Expensive work can happen at build time or request time | Data depends on client-side state |
When is it worth it? As a rule of thumb, memoize when the computation takes more than ~1ms or when the result is used as a dependency for useEffect, useCallback, or passed to a React.memo child.
useMemo when the computation takes more than ~1ms (profile first).useEffect, useCallback, or passed to a React.memo child.useMemo.useMemo is a performance optimization, not a semantic guarantee.Object.is, so a new reference means "changed."useMemo(() => value, deps) caches the return value of the factory function.useCallback(fn, deps) caches the function itself (equivalent to useMemo(() => fn, deps)).useMemo for values, useCallback for functions.useMemo runs during rendering, so side effects (fetching, subscriptions, DOM mutations) break React's rules.useEffect or event handlers.const options = useMemo(
() => ({ page, pageSize, sortBy }),
[page, pageSize, sortBy]
);
useEffect(() => {
fetchData(options);
}, [options]); // stable reference, effect only re-runs when values changeinterface Config {
retries: number;
timeout: number;
}
const config = useMemo<Config>(
() => ({ retries: 3, timeout: 5000 }),
[]
);
// config: ConfiguseMemo itself has overhead -- storing the value, comparing dependencies, and maintaining the cache.const chart = useMemo(
() => <ExpensiveChart data={data} />,
[data]
);data hasn't changed.React.memo on the component itself for most cases.useMemo is for client-side computation that depends on client state.useMemo(() => items.reduce((sum, i) => sum + i.price, 0), [items]) infers number.useMemo for functionsuseMemo to avoid re-running effectsReviewed by Chris St. John·Last updated Jul 16, 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥