Skip to main content

What does useCallback() do?

What useCallback() does

useCallback() is a function-memoization hook. It returns the same function (by reference) across renders, as long as the dependencies haven't changed.


Syntax:

javascript
const memoizedCallback = useCallback(callback, [deps]);
  • callback is the function you want to "remember".
  • [deps] is the array of dependencies this function relies on.

Example without useCallback

javascript
function App() { const handleClick = () => console.log('click'); return <Button onClick={handleClick} />; }

Every time the App component re-renders, React creates a new function handleClick. Even if the logic inside hasn't changed, the reference is different.

If Button is memoized (React.memo), React will think:

"The onClick prop changed (a new reference), I need to re-render the child."

Result: Button gets an unnecessary re-render.


With useCallback

javascript
function App() { const handleClick = useCallback(() => console.log('click'), []); return <Button onClick={handleClick} />; }

Now:

  • handleClick is created once;
  • On the next render, React returns the same reference (if the dependencies haven't changed);
  • For the memoized React.memo child component, the onClick prop hasn't changed;
  • -> the child component doesn't re-render.

How it works "under the hood"

React keeps the "old" version of the function in memory. On the next render:

  • It compares the dependencies [deps];
  • If nothing has changed, it returns the old function reference from memory;
  • If at least one dependency changed, it creates a new function and remembers it.

A visual example

javascript
function Parent() { const [count, setCount] = useState(0); const handleClick = useCallback(() => { console.log('clicked'); }, []); // empty dependencies -> the reference is stable console.log('Parent render'); return ( <> <Child onClick={handleClick} /> <button onClick={() => setCount(c => c + 1)}>+</button> </> ); } const Child = React.memo(({ onClick }) => { console.log('Child render'); return <button onClick={onClick}>Child</button>; });

Without useCallback:

javascript
Parent render Child render Parent render Child render (unnecessary)

With useCallback:

javascript
Parent render Child render Parent render (Child does not re-render)

When useCallback really helps

Use it if:

  1. The callback is passed into a memoized child component (React.memo, useMemo, etc.);
  2. The callback is part of the dependencies of another useEffect / useMemo, and you want to avoid false reruns.

When useCallback is not needed

  • If the function is used only inside the component (not passed to children in JSX).
  • If the child is not memoized (no React.memo).
  • If the component re-renders every time anyway (for example, the parent has no optimization).

useCallback does not speed up the function's execution. It only keeps the reference stable, so React doesn't think it's "new".


Parallel with useMemo

HookWhat it cachesReturns
useMemo(fn, deps)the result of a computationa value
useCallback(fn, deps)the function itselfa function

An equivalence example:

javascript
useCallback(fn, deps)useMemo(() => fn, deps);

Frequent pitfalls in usage

Wrong dependencies: If you don't add the dependencies, React will use stale data from the closure.

javascript
// the count dependency is missing -> stale closure const onClick = useCallback(() => console.log(count), []);

Correct:

javascript
const onClick = useCallback(() => console.log(count), [count]);

Summary

What useCallback doesHow it helps
Caches the function across rendersAvoids needlessly creating new functions
Returns the same reference if dependencies haven't changedProps on child components don't "change"
Works together with React.memoGenuinely avoids re-rendering the child
Doesn't speed up the code or reduce CPU loadOnly stabilizes the reference

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.