When do useMemo and useCallback actually help performance?
Take a moment.
Say your answer out loud or write it down first — retrieval is what makes it stick. Reveal when you're ready.
Short answer
They cache computation results (useMemo) and function identity (useCallback) between renders. They help when skipping expensive calculations or preserving referential equality — e.g., feeding memoized children or stable effect dependencies. Otherwise they add overhead.
Detailed explanation
Every render recreates objects, arrays and functions, breaking referential equality. useMemo caches a value until its dependencies change; useCallback returns a memoized version of a callback (it's useMemo for functions). Two legitimate wins: avoiding genuinely expensive recomputation (large sorts, heavy filtering), and referential stability — keeping a child wrapped in React.memo from re-rendering when it receives 'new' props every time, or preventing effect churn caused by unstable deps. Everything else is premature optimization: memoization itself costs memory and comparison work, and naive wrapping everywhere complicates code without measurable gains. Measure first with the Profiler. Also note they don't make renders cheaper by themselves — React.memo on components and virtualization for long lists usually matter far more.
Official docs:React docs: useMemo
Example
// Expensive calc — worth caching:
const sorted = useMemo(
() => [...rows].sort(expensiveComparator),
[rows],
);
// Stable identity for memoized child:
const onSave = useCallback(id => updateRow(id), []);
<MemoizedRow id={row.id} onSave={onSave} />Interview tip
State the two valid reasons (expensive compute, referential equality), then say 'measure with the Profiler first' — restraint signals seniority here.
Common mistakes
- Wrapping every variable in useMemo hoping to speed up renders.
- Not realizing useCallback(fn, []) still captures stale closures.