useMemo vs useCallback: The Practical Difference

useMemo caches the result of a calculation, and useCallback caches the function itself. Learn the practical difference and when each one is worth adding.

6 min read

useMemo caches a value, and useCallback caches a function. The difference is what each Hook stores. useMemo returns the result of calling a function, while useCallback returns the function itself without calling it, and both are performance optimizations rather than correctness tools.

The difference at a glance

HookWhat it cachesWhat it returnsTypical use
useMemoResult of a calculationThe calculated valueExpensive value or a stable object or array
useCallbackThe function definitionThe same functionStable function for a memo child or Hook dependency

Both Hooks take a dependency array, and both skip work only when every dependency is unchanged from the previous render, compared with Object.is.

The table answers the most common confusion. One Hook stores the outcome of running code, and the other stores the code itself. Pick the one that matches what must stay identical between renders.

When to use useMemo

Use useMemo when a calculation is expensive or when the result must keep the same reference across renders. A common case is an object passed to a child wrapped in memo.

App.jsxApp.jsx
import { useMemo } from "react";
 
function ProductPage({ productId }) {
  const requirements = useMemo(
    () => computeRequirements(productId),
    [productId]
  );
 
  return <ShippingForm requirements={requirements} />;
}

Here computeRequirements returns a requirements object. Because it is wrapped in useMemo, the object keeps the same reference until productId changes, so a memoized ShippingForm can skip re-rendering when the parent re-renders for another reason.

How do you know a calculation is expensive enough to bother? Wrap it in console.time and console.timeEnd, then perform the interaction.

If the logged time per update is meaningful, for example a millisecond or more, caching the result can help. Filtering or sorting thousands of rows is the kind of work where that happens.

The same pattern applies when the value feeds another Hook. If a useMemo result or a useEffect dependency is an object created inside the component, caching that object keeps it from changing on every render and restarting downstream work.

When to use useCallback

Use useCallback when a function must keep the same reference across renders, usually because it is passed to a memoized child or used as a dependency of another Hook.

App.jsxApp.jsx
import { useCallback } from "react";
 
function ProductPage({ productId }) {
  const handleSubmit = useCallback(
    (orderDetails) => {
      post(`/product/${productId}/buy`, orderDetails);
    },
    [productId]
  );
 
  return <ShippingForm onSubmit={handleSubmit} />;
}

The post function sends the order. Wrapping the handler in useCallback means handleSubmit is the same function until productId changes, so a memoized ShippingForm receives a stable prop. The same applies when a function is a dependency of another Hook, such as an Effect that reconnects when the function identity changes.

Remember that useCallback does not stop the function from being created. A new function is still created on every render, and React simply returns the cached one when the dependencies have not changed. The win is identity, not the cost of creating the function.

They are the same underneath

useCallback is shorthand for a specific useMemo pattern. Writing useCallback(fn, deps) is the same as writing useMemo(() => fn, deps).

The only difference is convenience. useCallback avoids the extra nested arrow function, and its name signals that the cached thing is a function.

Neither is a guarantee

These Hooks are performance optimizations, not semantic guarantees. React may throw away a cached value in some situations, and in development Strict Mode calls the calculation twice to surface accidental impurities.

They also never speed up the first render, which always runs the calculation or creates the function in full. Treat them as a way to skip repeated work after you have measured it, not as a correctness tool.

Which should you use?

  • Cache a value with useMemo when the calculation is slow or the reference matters.
  • Cache a function with useCallback when the function reference matters.
  • Skip both when nothing consumes the stable reference.

If no child is wrapped in memo and no Effect depends on the value, the wrappers are noise. memo only skips a render when props are stable, and both Hooks exist to keep those props stable. Confirm the re-render first with the Profiler, and remember that React Compiler can apply this memoization for you.

Rune AI

Rune AI

Key Insights

  • useMemo caches the result of calling a function.
  • useCallback caches the function itself without calling it.
  • useCallback(fn, deps) equals useMemo(() => fn, deps).
  • Both only help when the stable value is consumed as a prop or dependency.
  • Measure first, then memoize the value the Profiler shows changing.
RunePowered by Rune AI

Frequently Asked Questions

Can I always replace useCallback with useMemo?

Yes. useCallback(fn, deps) is equivalent to useMemo(() => fn, deps). useCallback exists only to avoid the extra nested function.

Do useMemo and useCallback make the first render faster?

No. They help skip work on later renders. The first render always runs the calculation or creates the function.

Conclusion

Use useMemo when a calculated value is expensive or must keep a stable identity, and use useCallback when a function must keep a stable identity. Both are performance optimizations, not guarantees, and both only pay off when the stable value or function is consumed by a memo child or a Hook.