performance
useCallback
Returns a memoized version of a callback whose identity stays stable until a dependency changes. Reach for it when passing callbacks to memoized children (React.memo) or as dependencies of other hooks that would otherwise re-run on every render.
const memoized = useCallback(fn, [deps]) Parameters & Behavior
| Parameter | Purpose |
|---|---|
| fn | The function to memoize |
| dependencies | Recreate the function only when any dep changes |
| equivalent to useMemo | useCallback(fn, deps) === useMemo(() => fn, deps) |
| stable identity | Prevents child re-renders when the child is wrapped in React.memo |
Examples
const handleClick = useCallback(() => setCount(c => c + 1), []);
return <ExpensiveChild onClick={handleClick} />; Stable handler lets React.memo(ExpensiveChild) skip re-rendering
const load = useCallback(() => fetch(`/api/${id}`).then(r => r.json()), [id]);
useEffect(() => { load().then(setData); }, [load]); Include a memoized callback in another effect's deps safely
const onSelect = useCallback((row) => setSelectedId(row.id), []); Row handlers stay identical across renders — big win in virtualized tables
const debouncedSearch = useCallback(debounce((q) => search(q), 300), [search]); Keeps the same debounced instance until `search` changes
Gotcha
Wrapping every function is cargo culting — it costs memory and only pays off with a memoized consumer or a hook dep. Missing deps produce stale closures the same way useEffect does.
Related hooks
useMemo
Memoizes the result of a computation between renders, recomputing only when a dependency changes. Reach for it when a calculation is genuinely expensive or when you need a stable reference (e.g. as a dep of another hook or a context value).
useEffect
Runs a side effect after the browser has painted the committed render. Reach for it for subscriptions, data fetching, DOM syncing with external systems, timers, and anything that must not block the visual update.
useState
Declares a piece of local state in a function component and returns the current value along with a setter. Reach for it whenever a component needs to remember a value across renders and re-render when that value changes.