Capítulo 49 de 116

Chapter 49: useCallback

Core Idea

useCallback(fn, dependencies) returns the same function reference across renders as long as the listed dependencies haven't changed, letting a function be passed to a memoized child (memo) or an Effect's dependency array without causing unnecessary re-renders/re-runs purely because a new closure was created.

Key Concepts

  • The problem it solves: every render of a component creates brand-new function instances for any inline function defined in its body — even if the logic is identical, the reference differs, which defeats memo's prop-equality check and forces Effects that depend on that function to re-run every time.
  • Signature: const cachedFn = useCallback(fn, [deps]) — React caches fn and returns the cached version unless a dependency changed since the last render, mirroring useMemo's dependency-array semantics.
  • useCallback(fn, deps) is equivalent to useMemo(() => fn, deps) — it's a convenience specifically for the function-caching case, not a fundamentally different mechanism.
  • Only worth it when the identity matters downstream: wrapping every handler in useCallback "just in case" adds overhead without benefit if nothing consuming that function actually depends on stable identity (no memoized child receiving it as a prop, no Effect depending on it).
  • With React Compiler (Ch 42), this memoization becomes largely automatic — the compiler inserts the equivalent optimization where safe, reducing (though the docs don't say eliminating) the need to reach for useCallback manually.

Code Examples

const handleSubmit = useCallback((orderId) => {
  post('/orders', { orderId, productId });
}, [productId]); // stable reference unless productId changes
  • What it demonstrates: a handler passed down to a memoized child component keeping a stable identity across re-renders that don't change productId.

Key Takeaways

  1. Reach for useCallback when a function is passed to a memo-wrapped child or used as an Effect dependency — not as a default wrapper for every function.
  2. It doesn't prevent the function from being created each render (the inline fn is still evaluated) — it only affects which reference gets returned and cached.
  3. React Compiler adoption reduces, but doesn't eliminate, the value of understanding this Hook — existing manual useCallback calls remain valid.

Connects To

  • Ch 59 (useMemo): the value-caching sibling this Hook's mechanics mirror.
  • Ch 88 (memo): the child-component wrapper whose prop-equality check this Hook's stable identity is usually for.
  • Ch 40 (Removing Effect Dependencies): functions as unstable Effect dependencies, the other major use case.