The Cost Nobody Mentions
useCallback has a cost. On every render, React has to compare the current dependency values to the previous ones. That comparison takes time. For a callback that's recreated on every render anyway (because a dependency changed), you've added the comparison overhead on top of the recreation cost — making things strictly slower.
The React profiler showed me callbacks in my parent component that were being memoized but whose dependencies changed on every render anyway, because one of those dependencies was an object literal defined inline. The useCallback wrapper was pure overhead. Every render, comparison ran. Every render, callback was recreated.
When useCallback Actually Helps
useCallback genuinely helps in two situations: when you're passing a callback to a child wrapped in React.memo, and when a callback is a dependency of another hook like useEffect. Outside of those cases, you're adding complexity for zero benefit.
My rule now: don't reach for useCallback until the profiler shows you a problem. Measure first. The default should be the simplest code — plain inline functions. Optimization is a response to evidence, not a precaution.
Key takeaways
- useCallback only helps when passed to React.memo children or used as a dependency in another hook — outside these cases it adds overhead without benefit
- Always profile before optimizing — React DevTools Profiler shows exactly which components re-render and why
- Object and array literals as hook dependencies recreate on every render, defeating memoization — move them outside the component or useMemo them
Conclusion
Premature optimization is still the root of a lot of evil, even when it comes in the form of a React hook. The profiler is your friend. Use it before adding memoization, not after.
Enjoyed this article?

Vivek Kumar Singh
Technical Expert · Full Stack Cloud Engineer · Tokyo, Japan