Originally written in 2020. Republished here with minor wording updates.
useCallback exists for one reason:
to stop React from recreating functions when it doesn’t need to.
Because yes — React loves re-rendering.
And yes — functions get a new identity every time.
The problem (in one sentence)
Every render creates new functions, and React treats them as different, even if the code looks the same.
This can cause:
- unnecessary child re-renders
- wasted work
- confused debugging sessions
What useCallback actually does
useCallback memoizes a function.
It returns the same function reference as long as its dependencies don’t change.
const memoizedFn = useCallback(fn, deps);
Same deps → same function
Changed deps → new function
Simple.
When useCallback is worth using
Use it when:
- You pass a function to a memoized child component
- You care about function identity, not just logic
- A callback is recreated often and causes re-renders
If none of those apply?
You probably don’t need it.
Quick example
import { useState, useCallback } from "react";
function Parent() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount((c) => c + 1);
}, []);
return <Child onClick={increment} />;
}
Without useCallback, increment is new on every render.
With it, React can finally relax.
Pro tip (read this twice)
useCallbackis about reference stability, not performance magic.
Overusing it:
- adds complexity
- increases mental overhead
- often changes nothing
Memoize intentionally, not defensively.
Seeing it in action
Here’s a small demo that counts how many times functions are recreated:
const functionsCounter = new Set();
Each time a new function is created, it’s added to the set.
Stable functions = smaller number = happier brain.
🚀 Try it on CodeSandbox:
https://codesandbox.io/s/usecallback-k8zzs
Final thought
useCallback won’t make your app faster by default.
But when you need stable function references, it’s the right tool.
Use it wisely — and React will stop fighting you (a little).
Top comments (0)