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:
const memoizedCallback = useCallback(callback, [deps]);callbackis the function you want to "remember".[deps]is the array of dependencies this function relies on.
Example without useCallback
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
onClickprop changed (a new reference), I need to re-render the child."
Result: Button gets an unnecessary re-render.
With useCallback
function App() {
const handleClick = useCallback(() => console.log('click'), []);
return <Button onClick={handleClick} />;
}Now:
handleClickis created once;- On the next render, React returns the same reference (if the dependencies haven't changed);
- For the memoized
React.memochild component, theonClickprop 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
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:
Parent render
Child render
Parent render
Child render (unnecessary)With useCallback:
Parent render
Child render
Parent render (Child does not re-render)When useCallback really helps
Use it if:
- The callback is passed into a memoized child component (
React.memo,useMemo, etc.); - 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).
useCallbackdoes not speed up the function's execution. It only keeps the reference stable, so React doesn't think it's "new".
Parallel with useMemo
| Hook | What it caches | Returns |
|---|---|---|
useMemo(fn, deps) | the result of a computation | a value |
useCallback(fn, deps) | the function itself | a function |
An equivalence example:
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.
// the count dependency is missing -> stale closure
const onClick = useCallback(() => console.log(count), []);Correct:
const onClick = useCallback(() => console.log(count), [count]);Summary
What useCallback does | How it helps |
|---|---|
| Caches the function across renders | Avoids needlessly creating new functions |
| Returns the same reference if dependencies haven't changed | Props on child components don't "change" |
Works together with React.memo | Genuinely avoids re-rendering the child |
| Doesn't speed up the code or reduce CPU load | Only stabilizes the reference |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.