useMemo and useCallback: When Memoization Actually Helps

useMemo and useCallback are caching tools. They can speed up a slow component — or just add noise to a fast one. Knowing the difference keeps your code both fast and readable.

What they do

useMemo caches a computed value; useCallback caches a function. Both recompute only when their dependencies change:

const sorted = useMemo(
  () => items.slice().sort(compare),
  [items]
);

const handleClick = useCallback(
  () => doSomething(id),
  [id]
);

(useCallback(fn, deps) is just useMemo(() => fn, deps) with nicer ergonomics.)

When memoization helps

  • The calculation is genuinely expensive (sorting/filtering large lists, heavy math).
  • You pass an object or function to a React.memo child and need its reference to stay stable so the child can skip re-rendering.
  • A value is a dependency of another hook (like useEffect) and you need it to stay referentially stable.

When to skip it

For cheap calculations, memoization can cost more than it saves: it adds a dependency array to maintain, a cache to store, and code to read. Wrapping every value "just in case" is a common anti-pattern. Measure first — most components are fast enough without it.

// Pointless — the work is trivial
const doubled = useMemo(() => count * 2, [count]);

// Just write:
const doubled = count * 2;

Key takeaways

  • useMemo caches a value; useCallback caches a function.
  • Use them for expensive work or to keep references stable for memoized children/effects.
  • Don't memoize trivial values — it adds complexity without benefit.
  • Profile before optimising; correctness and readability come first.

Want the structured path? Explore the React roadmap or browse more articles.