useMemo
useMemo memoises an expensive computed value, recomputing only when its dependencies change. Use it for actually-expensive work or to keep referential equality for downstream memo children — not by default.
When to memoise, when not to
EXAMPLE
import { useMemo, useState, memo } from 'react';
// 1) Expensive derivation — list filtering and sorting
function Table({ rows, query }) {
const filtered = useMemo(() => {
return rows
.filter(r => r.name.toLowerCase().includes(query.toLowerCase()))
.sort((a, b) => a.score - b.score);
}, [rows, query]);
return <List items={filtered} />;
}
// 2) Stable reference for a memoised child
const HeavyChild = memo(function HeavyChild({ config }) {
// ...
});
function Parent({ theme }) {
// Without useMemo, config is a new object each render → HeavyChild always re-renders
const config = useMemo(() => ({ theme, threshold: 5 }), [theme]);
return <HeavyChild config={config} />;
}
// 3) Avoid memoising primitives
// const x = useMemo(() => count + 1, [count]); // unnecessary — just compute it inline
// 4) Don't memoise everything
// useMemo costs memory + dep-array bookkeeping. For cheap work, raw recomputation wins.
// 5) Pair with useCallback for function props to memoised children
import { useCallback } from 'react';
function Filters({ onSubmit }) {
const handleClick = useCallback(() => onSubmit(state), [onSubmit, state]);
return <Button onClick={handleClick} />;
}
// 6) Common bugs
// 6a) Wrong dep array — stale value
// const sorted = useMemo(() => sort(rows), []); // rows updates ignored
// 6b) Memoising a Date/random/Math.random — non-deterministic
// const now = useMemo(() => Date.now(), []); // freezes on first render
// 6c) Treating useMemo as a side-effect — never do work with effects inside
// const x = useMemo(() => { fetch(url); return ...; }, []); // bad
// 7) Profile FIRST. React DevTools → Profiler.
// If a component isn't slow, useMemo just adds noise.
Why it matters
useMemo is a perf tool, not a correctness tool. Reach for it when a computation is measurably expensive or when downstream memo children need stable references — not by default.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
const expensive = useMemo(
() => bigList.filter(i => i.active).map(transform),
[bigList],
);
Try it Yourself »
Discussion
Loading…