React useCallback — When and How to Memoize Functions

Learn when to use useCallback in React for performance optimization. Covers stable function references, React.memo integration, dependency management, and common over-optimization mistakes.

Performance Hooks

Detailed Explanation

Function Memoization with useCallback

useCallback returns a memoized version of a function that only changes when its dependencies change. It is a performance optimization for preventing unnecessary re-renders.

The Problem It Solves

In React, every render creates new function instances:

function Parent() {
  // New function on every render
  const handleClick = (id: number) => console.log(id);

  // Child re-renders every time, even with React.memo
  return <MemoizedChild onClick={handleClick} />;
}

The Solution

function Parent() {
  const handleClick = useCallback((id: number) => {
    console.log(id);
  }, []); // Stable reference

  return <MemoizedChild onClick={handleClick} />;
}

When useCallback Actually Helps

  1. Passing callbacks to memoized children (React.memo)
  2. Function used as a dependency in useEffect, useMemo, or another useCallback
  3. Custom hooks that return functions consumers might use as effect dependencies

When NOT to Use useCallback

  • On every function "just in case" -- the memoization overhead may exceed the re-render cost
  • Without React.memo on the receiving component
  • For event handlers on native DOM elements (React handles these efficiently)
  • For inline functions that do not cause measurable performance issues

Functional Updates to Avoid Dependencies

// Instead of depending on count:
const increment = useCallback(() => {
  setCount(prev => prev + 1);
}, []); // No dependencies needed

Use Case

Use useCallback when passing callbacks to React.memo-wrapped children, when functions serve as effect dependencies, and in custom hooks that return callback functions. Always profile before optimizing.

Try It — React Hooks Reference

Open full tool