Q&A
What is the useMemo hook in React?
Overview
React components re-render often, and every render re-runs the function body - including any expensive calculations. useMemo caches a computed value across renders, recomputing only when the inputs (dependencies) change. It's purely an optimization: your app should work correctly without it; useMemo just avoids wasted work and unnecessary re-renders.
graph TD
A[Component re-renders] --> B{Dependencies changed?}
B -->|yes| C[Re-run the computation, cache result]
B -->|no| D[Return the cached value, skip work]
C & D --> E[Use the value]
style D fill:#1e1b4b,color:#fff
Syntax
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
- First arg: a function that returns the value to cache.
- Second arg: the dependency array - recompute only when one of these changes.
Use Case 1: Skip Expensive Calculations
function ProductList({ products, filter }) {
const filtered = useMemo(() => {
// imagine this is expensive (large list, heavy transform)
return products.filter(p => p.name.includes(filter)).sort(/* ... */);
}, [products, filter]); // recompute only when products or filter change
return <ul>{filtered.map(p => <li key={p.id}>{p.name}</li>)}</ul>;
}
Without useMemo, the filter+sort runs on every render (e.g. when an unrelated state changes). With it, the work happens only when products or filter actually change.
Use Case 2: Referential Stability
JS creates a new object/array each render, which can break React.memo children or trigger other hooks' dependencies. useMemo preserves the same reference when inputs are unchanged:
// Without useMemo, `config` is a new object each render →
// MemoChild re-renders every time even if values are identical.
const config = useMemo(() => ({ color, size }), [color, size]);
return <MemoChild config={config} />; // now only re-renders when color/size change
This is a common, legitimate reason to use useMemo even when the computation itself is cheap.
useMemo vs useCallback
They're siblings:
useMemo(fn, deps)caches the value thatfnreturns.useCallback(fn, deps)caches the function itself (equivalent touseMemo(() => fn, deps)). UseuseCallbackfor stable function references (e.g. passing callbacks to memoized children);useMemofor stable/computed values.
When NOT to Use It
useMemo isn't free - it adds memory and a dependency check, and clutters code. Don't memoize trivial calculations; the overhead can exceed the savings. Use it when:
- A computation is genuinely expensive, or
- You need referential stability for a value passed to
React.memo/hook dependencies.
Premature useMemo everywhere is an anti-pattern. (Note: the React Compiler, when adopted, can automate much of this memoization.)
Correct Dependencies
Include every value from the component scope used inside the function. Omitting dependencies yields stale values; the eslint-plugin-react-hooks exhaustive-deps rule catches this.
Why This Matters in Interviews
React interviews use useMemo to test performance understanding. Key points: it caches a computed value and recomputes only when dependencies change; two valid uses (expensive computation and referential stability for memoized children/hook deps); the distinction from useCallback (value vs function); and the maturity to say it's an optimization that shouldn't be applied blindly. Correct dependency arrays (and the exhaustive-deps rule) are a frequent follow-up.
Common Pitfalls
- Overusing
useMemoon cheap computations, adding overhead and noise. - Wrong/missing dependencies → stale cached values.
- Expecting it to fix correctness bugs (it's only an optimization).
- Confusing it with
useCallback(which memoizes a function, not its return value). - Memoizing values that change every render anyway (no benefit).
References
- React
useMemo: https://react.dev/reference/react/useMemo - React
useCallback: https://react.dev/reference/react/useCallback