Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Use memo, useMemo, and useCallback only when profiling shows that a component render or calculation is costly and avoidable. memo can let a component skip rendering when its props are unchanged; useMemo caches a calculation result; and useCallback keeps a function’s identity stable. None guarantees faster code, and React Compiler can now automate many of these optimizations.

What each React memoization tool can skip

Tool What it can avoid When it can help
memo A component render when its props are unchanged. A profiled, expensive child often receives the same props.
useMemo Repeating a calculation when its dependencies are unchanged. A costly calculation runs during rendering, or a stable object or array prop is needed for a memoized child.
useCallback A changed function identity between renders. A callback is passed to a memoized child or used as a Hook dependency and its identity needs to remain stable.

These tools address different work. They are performance optimizations, not correctness tools: React’s documentation describes memo as a performance optimization, not a guarantee and says to rely on useMemo only as a performance optimization.

Why a memoized child may still render

By default, memo compares each prop with Object.is. If a parent creates a new object, array, or function while rendering, that prop has a new identity even when its contents or behavior look equivalent. The memoized child therefore sees a changed prop and may render.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A common chain looks like this: a parent renders, creates a fresh value or callback, and passes it to a memoized child. To give the child a chance to skip rendering, stabilize the value with useMemo or the callback with useCallback. The child can skip only if its other relevant props are unchanged too.

memo does not block a render caused by the child’s own state or by context it reads. A custom comparison function is available when the default prop comparison is insufficient, but it introduces another piece of logic to maintain and should be considered only after measurement.

Stabilize a calculated value with useMemo

useMemo caches the result of a calculation between renders while its dependencies remain unchanged. React compares each dependency with Object.is. Include every reactive value used by the calculation in the dependency list.

const visibleItems = useMemo(() => filterItems(items, query), [items, query]);

This example can avoid repeating filterItems when neither items nor query changed. It can also give a memoized child a stable array prop, provided the dependencies remain stable and the child’s other props do not change.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep the calculation pure: it should compute a result from its inputs rather than cause side effects. Do not use a memoized value to conceal incorrect behavior or make rendering depend on a cache being present.

Stabilize a callback with useCallback

useCallback caches a function definition while its dependencies remain unchanged. It does not prevent JavaScript from evaluating the function expression during rendering; it preserves the function identity React returns when the dependencies are the same.

const handleSelect = useCallback((id) => {
  setSelectedId(id);
}, []);

Use this when a stable callback matters, such as when passing it to a memoized child. If the callback reads reactive values, include those values as dependencies so it does not use stale data. React compares dependencies with Object.is.

Diagnose the slowdown before adding memoization

  1. Reproduce the sluggish interaction. Identify the specific action that feels slow rather than optimizing components based on appearance alone.
  2. Profile the interaction. Use the React Developer Tools Profiler to find which renders or calculations consume meaningful time.
  3. Check simpler causes. Look for Effects that set state and trigger extra renders, state placed higher in the tree than necessary, and props whose object, array, or function identities are always new.
  4. Make the smallest measured change. Apply the relevant memoization tool, then profile the same interaction again and check that the behavior remains correct.

React recommends prioritizing pure rendering, keeping state appropriately local, and avoiding unnecessary Effects. If an object or function is only needed inside an Effect, moving it inside that Effect—or outside the component when appropriate—can be simpler than memoizing it just to control Effect dependencies.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When manual memoization is unnecessary

  • The component or calculation is already fast, and profiling does not show it as a meaningful cost.
  • The props or dependencies change on most renders, so the cache rarely avoids work.
  • Memoization adds complicated dependency lists or obscures straightforward code.
  • The real issue is repeated state updates, an unnecessarily broad state owner, or an Effect that causes extra renders.
  • React Compiler is enabled and handles the optimization automatically.

React’s current guidance is not to add memoization everywhere. The React Compiler introduction explains that the compiler can automatically memoize components, values, and functions. For new code, React recommends relying on the compiler where it is enabled; manual memo, useMemo, and useCallback remain available when you need precise control.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

A practical decision rule

  • If a profiled child spends significant time rendering despite unchanged props, consider memo.
  • If a profiled calculation is expensive and its inputs often remain unchanged, consider useMemo.
  • If a callback’s changing identity prevents a memoized child from skipping a render, consider useCallback.
  • If none of these conditions applies, prefer simpler code and revisit optimization only when a real performance problem appears.

For the broader compiler behavior and setup context, see React’s React Compiler documentation.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.