
React useCallback Hook Explained with Examples and Best Practices (2025 Guide)
- bilalshafqat42
- June 25, 2025
- React Hooks, React Js
- 0 Comments
Introduction
React’s useCallback
is one of those hooks that seems confusing at first — until you start dealing with unnecessary re-renders or memoized components.
In React, functions are re-created on every render. This behavior is harmless in most cases, but when passing callbacks to deeply nested or memoized child components, re-creating the function can cause unnecessary re-renders and performance issues.
This is where useCallback
shines.
In this guide, you’ll learn:
- What
useCallback
is - How it works and why it exists
- How it compares to
useMemo
and inline functions - When to use it — and when not to
- Real-world use cases with code examples
What is useCallback?
useCallback
is a built-in React hook that lets you memoize a function — meaning it returns the same function reference between renders unless one of its dependencies has changed.
Syntax:
const memoizedFn = useCallback(() => {
// your logic
}, [dependencies]);
If none of the dependencies change, React will return the exact same function — avoiding unnecessary function recreation and preventing extra renders in child components.
Why is this useful?
When you pass a function as a prop to a memoized child component (e.g., using React.memo
), even a new function reference — with identical logic — can cause that component to re-render.
useCallback
ensures that the function reference remains stable, helping with performance and preventing extra renders.
Example 1: Memoizing a Handler
import { useCallback, useState } from 'react';
function Parent() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount(c => c + 1);
}, []);
return <Child onClick={increment} />;
}
Without useCallback
, the increment
function would be re-created on every render, potentially triggering unnecessary renders in Child
.
useCallback vs useMemo
Both useCallback
and useMemo
help with memoization — but they do different things.
Feature | useCallback | useMemo |
---|---|---|
Purpose | Memoize functions | Memoize values (returned from functions) |
Return type | A function | Any value (array, object, result) |
Use case | Event handlers, props | Expensive calculations, filtered arrays |
Example 2: useCallback vs Inline Function
Inline Function:
<Button onClick={() => doSomething()} />
With useCallback:
const handleClick = useCallback(() => doSomething(), []);
<Button onClick={handleClick} />
In the first case, a new function is created every render.
In the second case, handleClick
stays the same between renders — avoiding unnecessary re-renders of Button
.
Real Use Case: Avoid Re-rendering Memoized Children
const Child = React.memo(({ onClick }) => {
console.log("Child rendered");
return <button onClick={onClick}>Click</button>;
});
function Parent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log("Clicked");
}, []);
return (
<>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<Child onClick={handleClick} />
</>
);
}
Here, Child
will NOT re-render unless handleClick
changes — which it won’t, thanks to useCallback()
.
When to Use useCallback
- You’re passing a function as a prop to a memoized child component
- You want to avoid unnecessary function recreation
- You’re building reusable components or component libraries
- You’re using a stable callback in an effect
When NOT to Use useCallback
- Your function doesn’t affect performance when recreated
- You’re not passing it to memoized children
- Your dependencies change frequently (useCallback won’t help much)
Note: Don’t use useCallback
everywhere “just in case.” It adds complexity and memory overhead. Use it when it solves a specific performance issue.
Common Mistakes with useCallback
1. Overusing it
Don’t wrap every function in useCallback
by default. Only use it for actual memoization needs.
2. Missing dependencies
useCallback(() => {
doSomething(message);
}, []); // 🚫 'message' should be in dependencies
3. Using it without memoized children
If you’re not using React.memo
or passing functions to children, useCallback
might have no benefit.
Best Practices for useCallback (2025)
- Use with
React.memo
to prevent child re-renders - Use with stable dependencies to avoid re-creating the function
- Combine with
useEffect
when passing a callback that must not change - Profile performance with dev tools before applying
- Clean up side effects when passing memoized callbacks to useEffect
Summary: Master useCallback to Improve React Performance
useCallback
is not just a “nice to have” — it’s essential when building performant React apps with lots of components or heavy rendering logic.
Remember:
- It returns a memoized version of your function
- It helps avoid unnecessary re-renders
- It should be used selectively — not everywhere
If you work with React.memo
, nested components, or reusable hooks — useCallback
is your best friend.