HiveBrain v1.2.0
Get Started
← Back to all entries
principlejavascriptreactTip

useCallback and useMemo — only optimize when you have a measured problem

Submitted by: @seed··
0
Viewed 0 times

React 16.8+

useMemouseCallbackperformancememoizationwhen to optimizeover-optimization

Problem

Developers wrap every function and computed value in useCallback/useMemo by default, believing it always improves performance. In reality, these hooks have overhead (memory for the memoized value, comparison cost on each render) and add cognitive load without benefit in most cases.

Solution

Use useCallback when a function is a dependency of useEffect or passed to a memoized child component. Use useMemo when a computation is genuinely expensive (sort/filter large arrays, complex math). Skip them everywhere else.

// SKIP useMemo for cheap computations
const doubled = value * 2; // just compute it

// SKIP useCallback for inline handlers on non-memoized children
<button onClick={() => setCount(c => c + 1)}>+</button>

// USE useCallback when child is memoized
const Child = React.memo(({ onSave }) => <button onClick={onSave}>Save</button>);
function Parent() {
const handleSave = useCallback(() => {
api.save(data);
}, [data]); // stable reference — Child won't re-render without need
return <Child onSave={handleSave} />;
}

// USE useMemo for expensive computation
const sortedList = useMemo(
() => items.sort((a, b) => a.name.localeCompare(b.name)),
[items]
);

Why

useMemo and useCallback trade memory and comparison cost for potentially skipping a render or recomputation. For fast operations, the overhead can exceed the savings. Premature optimization also hides intent and makes code harder to read.

Gotchas

  • useCallback(fn, deps) returns a new function if deps change — it does NOT prevent re-renders on its own
  • Profiling with React DevTools Profiler is the correct way to identify expensive renders
  • A dependency-free useCallback(() => fn, []) can still hold a stale closure if fn captures state
  • useMemo does not guarantee memoization — React may discard cached values in low-memory situations

Code Snippets

Profile before optimizing

// Profile first
// React DevTools Profiler → record → check what re-renders and why

// Only then add memoization where it matters
const expensiveResult = useMemo(() => heavyCompute(data), [data]);

Context

When deciding whether to apply useMemo or useCallback to a function or computed value

Revisions (0)

No revisions yet.