useCallback returns a memoized version of a function that only changes when dependencies change. It helps prevent child re-renders when passing callbacks to React.memo components.
Stable Function References
const fn = useCallback(() => doWork(a), [a]) is equivalent to useMemo(() => () => doWork(a), [a]). The cached function reference stays the same across renders if deps are unchanged.
Inline arrow functions in JSX create new references every render, which can break memoization of child components comparing props by reference.
React 19's experimental React Compiler can auto-memoize in some setups, reducing manual useCallback/useMemo. Until then, manual memoization remains common in performance-critical paths.
Common Mistakes
Wrapping every handler in useCallback without memoized children.
Stale closures from incomplete dependency arrays.
Using useCallback instead of fixing architecture problems.
Assuming useCallback speeds up the parent component.
Key Takeaways
useCallback memoizes function references.
Most useful with React.memo children and effect deps.
Not needed for most everyday event handlers.
Profile and measure before adding widely.
Pro Tip
React Docs now say: skip useCallback until profiling shows a child re-render problem. Good default advice.
You understand useCallback for stable functions. Next, manage complex state transitions with useReducer.