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 useMemo and useCallback when they solve a measured performance problem or preserve identity where another optimization depends on it—not as automatic wrappers for every value and function. For new React code, the official guidance is to rely on React Compiler for memoization when it is enabled, keeping manual hooks for cases that need precise control. Existing hooks should be left in place or removed only after careful testing.

What the hooks actually cache

useMemo caches a calculation result

useMemo(calculateValue, dependencies) runs the calculation during the initial render. On later renders, React returns the cached result if each dependency compares equal to its previous value using Object.is; otherwise, it runs the calculation again. The calculation must be pure. In Strict Mode, React may call it twice in development to help uncover impure calculations. It does not make the initial render faster. React’s useMemo reference explains the behavior and its limitations.

useCallback caches a function identity

useCallback(fn, dependencies) returns the same function identity on later renders while its dependencies remain equal under Object.is. It does not call fn, and it does not stop JavaScript from creating the inline function expression during rendering. The benefit is that React can return the previous function identity, which matters only when something downstream can use that stability. See React’s useCallback reference.

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

Both hooks require a constant-length dependency list written inline. Include every reactive value used by the calculation or callback; incomplete lists can leave stale values and interfere with compiler analysis. Follow the Hooks lint rules rather than suppressing dependency warnings.

When manual memoization earns its place

Use useMemo for measured work or useful stable identity

  • A calculation is noticeably slow in the interaction you profiled, and its inputs often remain unchanged between renders.
  • A stable object or array prop lets a child wrapped in memo skip work.
  • A value is a dependency of another Hook, and keeping its identity stable prevents unnecessary work there.

Memoization helps only when dependencies stay equal often enough to reuse the result, or when another optimization consumes the stable identity. If one prop is always new, it can defeat a memoized child even if its other props are stable. Inspect the whole path from the parent’s values to the child’s props.

Use useCallback when a consumer benefits from a stable function

  • You pass a callback to a component wrapped in memo, and stable identity allows that component to skip rendering.
  • The function is a dependency of another Hook and its identity would otherwise cause that Hook to do unnecessary work.

If no memoized child or Hook dependency benefits, an ordinary function is simpler. As with useMemo, a single changing dependency means React must return a new cached identity.

When to remove a wrapper—or avoid adding one

If there is no measured slow calculation and no identity-sensitive consumer, start with ordinary code. A small calculation or callback does not become faster merely because it is wrapped. React cautions that memoization is a performance optimization, not something code should rely on for correctness; the cache may be discarded in documented situations. Your component must still work correctly when a cached value or function is recreated.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Move a value that does not depend on props or state outside the component.
  • If an object or function exists only to be used by an Effect, consider creating it inside that Effect instead of memoizing it to control the dependency list.
  • Keep state close to the components that use it, so unrelated parts of the tree do not render in response to it.
  • For visual wrapper components, consider passing changing content as JSX children when that suits the component structure.
  • Avoid Effects that update state unnecessarily and trigger chains of additional renders. Fix impure rendering directly instead of trying to hide it with memoization.

These approaches simplify the component’s data flow and may remove the cause of extra work rather than adding another cache. React’s guidance on whether to add useMemo everywhere and whether to add useCallback everywhere emphasizes the trade-off: broad memoization may not cause significant harm for some teams, but it can reduce readability, and unstable values can make it ineffective.

How React Compiler changes the default

React Compiler analyzes React code at build time and can automatically memoize values, functions, and components in many cases. It is intended to reduce the need to add useMemo, useCallback, and memo by hand. Whether it can optimize a particular component depends on whether the compiler can understand the code and apply its analysis.

React’s Compiler 1.0 guidance, published October 7, 2025, says: “For new code, we recommend relying on the compiler for memoization and using useMemo/useCallback where needed to achieve precise control.” Read the React Compiler 1.0 announcement. This is not a promise that every project already has the compiler enabled: check your framework or build configuration, the compiler version, and compatibility against the current React Compiler setup documentation. Support and setup details can change.

For existing code, React advises leaving manual memoization in place or testing removals carefully because removing it can change compiler output. The compiler preserves existing manual memoization, and missing dependencies can prevent it from following data flow and applying further optimizations. Treat compiler adoption as a project configuration and migration decision, not an assumption based on using a recent React version.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

A practical way to decide

  1. Make the render path sound first. Keep state local where possible, keep rendering pure, and remove unnecessary Effect-driven update chains.
  2. Reproduce the slow interaction. Use React Developer Tools Profiler to identify which components render and where time is spent. Use representative data; CPU throttling can help reveal problems that are hard to reproduce on a fast machine. React documents the React Developer Tools and Profiler API.
  3. Check the actual bottleneck. Decide whether a calculation is slow, a child is doing avoidable work, or a Hook is rerunning because a dependency changes identity. Confirm that the proposed memoized value or function is consumed by a boundary that can benefit.
  4. Add the smallest targeted optimization. Use useMemo for a calculation result or stable value, and useCallback for a callback whose identity matters. Keep all reactive dependencies complete.
  5. Compare before and after in a production build. Development mode and Strict Mode can distort timings. Test the same representative interaction on a representative device, and keep the change only if it improves the relevant work without unacceptable complexity.
  6. Retest removals. When cleaning up existing hooks, check behavior and production performance rather than assuming fewer hooks means faster code—especially in a project using React Compiler.

There is no universal number of renders saved or percentage improvement to expect. The right comparison is the work and interaction latency in your own application, the stability of dependencies, whether an optimized boundary uses identity, correctness when dependencies change, and the readability cost of maintaining the wrapper.

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.