HuntExams Academy logo
ReactAdvanced#hooks#performance

Difference between useMemo and useCallback?

Answer

useMemo caches a computed value between renders; useCallback caches a function identity. Both take a dependency array and exist to avoid expensive recomputation or unnecessary re-renders of memoized children.

Example

const sorted = useMemo(() => items.sort(cmp), [items]);
const onPick = useCallback(id => setPick(id), []);

Detailed explanation

useMemo and useCallback are React Hooks that preserve something between renders when their dependencies remain unchanged. useMemo caches the result of a calculation, whereas useCallback caches a function reference. This distinction matters because each component render normally runs its calculations again and creates new functions declared inside it. Reusing a result can save computation; reusing a function reference can help another optimisation, such as React.memo, work effectively.

With useMemo(() => calculate(items), [items]), React calls the calculation during the initial render and stores its result. On later renders, React compares each dependency with its previous value using Object.is. If none changed, it returns the cached result; otherwise, it recalculates. For sorting, prefer const sorted = useMemo(() => [...items].sort(cmp), [items, cmp]);. The supplied items.sort(cmp) example mutates the original array, which is unsafe when items comes from props or state. Include cmp if it is a reactive value, such as a prop or a function declared inside the component; a stable module-level comparator need not be included.

With useCallback(id => setPick(id), []), React returns the same function reference across renders while dependencies remain unchanged. React does not execute the callback; an event handler or other caller does that later. JavaScript still creates the function passed to the Hook during rendering, but React can return the previously cached function instead. An empty dependency array is valid here if setPick is the setter returned by useState, because that setter has stable identity. Any props or state read by the callback must normally appear in its dependencies to avoid stale closures.

Neither Hook automatically prevents rendering. A stable callback helps a React.memo child skip parent-driven renders only when its other props also remain equal; its own state or consumed context can still trigger renders. Both Hooks are performance optimisations, not correctness guarantees or permanent storage. Interviewers look for dependency awareness, immutability, and evidence-based optimisation rather than adding memoisation everywhere.

Key points to remember

  • useMemo returns a cached calculation result; useCallback returns a cached function reference.
  • React compares dependencies using Object.is, not deep equality.
  • useCallback(fn, deps) is conceptually equivalent to useMemo(() => fn, deps).
  • Stable references can support React.memo, but do not independently prevent child renders.
  • Use memoisation for measured expensive work or meaningful reference stability, not every value and handler.

Common mistakes candidates make

  • Sorting props or state with items.sort(cmp), which mutates the source array; copy it before sorting.
  • Omitting reactive dependencies to force a stable reference, creating stale closures or outdated results.
  • Assuming useCallback stops function creation or guarantees that a child will not re-render.

Likely follow-up questions

How can a callback update state without depending on the current state value?

Use a functional updater when the next state depends only on the previous state: const increment = useCallback(() => setCount(c => c + 1), []);. React supplies the current pending state to the updater, so the callback does not need to capture count.

What happens if a dependency is a new object on every render?

Object.is treats each newly created object as different, so the cache is invalidated on every render. Where appropriate, construct the object inside the memoised calculation and depend on its primitive inputs instead.

Why might a useMemo calculation run twice in development?

React Strict Mode may invoke the calculation twice in development to help reveal impurities, ignoring one result. Keep the calculation pure: do not mutate inputs, perform network requests, or rely on it running exactly once.

Interview tip: Start with “cached value versus cached function identity,” then explain dependency comparison and correct the mutating sort example.

Related Interview Questions

1
ReactAdvanced#performance

What is React.memo?

Open
2
ReactIntermediate#hooks#context

What is useContext and when do you use it?

Open
3
ReactAdvanced#hooks#state

When should you use useReducer instead of useState?

Open