useMemo vs useCallback in React: A Step-by-Step Guide with Practical Examples
React applications re-render whenever state or props change. While this behavior is essential, unnecessary re-renders and expensive calculations can negatively impact your application's performance.
React provides two optimization hooks to solve these problems:
- ⚡
useMemo– Memoizes values - ⚡
useCallback– Memoizes functions
Although they seem similar, they solve different performance issues. In this guide, you'll learn when to use each hook and how to implement them correctly.
What is useMemo?
useMemo caches the result of an expensive calculation and only recalculates it when one of its dependencies changes.
Syntax
const memoizedValue = useMemo(() => {
return expensiveCalculation(data);
}, [data]);
Think of it as:
"Don't recalculate this value unless something important changes."
When Should You Use useMemo?
Use useMemo when:
- Filtering large arrays
- Sorting data
- Complex mathematical calculations
- Data transformations
- Expensive computations
Avoid using it for simple calculations because memoization itself has a small overhead.
Step 1: Without useMemo
Imagine we have thousands of products.
function ProductList({ products, search }) {
const filteredProducts = products.filter(product =>
product.title.toLowerCase().includes(search.toLowerCase())
);
return (
<>
{filteredProducts.map(product => (
<p key={product.id}>{product.title}</p>
))}
</>
);
}
Every render runs:
products.filter(...)
Even if products and search never changed.
Step 2: Optimize with useMemo
import { useMemo } from "react";
function ProductList({ products, search }) {
const filteredProducts = useMemo(() => {
return products.filter(product =>
product.title.toLowerCase().includes(search.toLowerCase())
);
}, [products, search]);
return (
<>
{filteredProducts.map(product => (
<p key={product.id}>{product.title}</p>
))}
</>
);
}
Now React only recalculates the filtered products when:
- products change
- search changes
Otherwise it reuses the cached value.
What is useCallback?
Unlike useMemo, useCallback memoizes functions, not values.
Without it, every render creates a brand new function.
const handleClick = () => {
console.log("Clicked");
};
Every render creates a new function reference.
Why is This a Problem?
Consider this component:
const Child = React.memo(({ onClick }) => {
console.log("Child Rendered");
return (
<button onClick={onClick}>
Click Me
</button>
);
});
Even though Child is wrapped with React.memo, it still re-renders because:
onClick !== previousOnClick
The function reference changes every render.
Step 3: Without useCallback
function Parent() {
const [count, setCount] = useState(0);
const handleClick = () => {
console.log("Clicked");
};
return (
<>
<button onClick={() => setCount(count + 1)}>
Count {count}
</button>
<Child onClick={handleClick} />
</>
);
}
Every time count changes:
- Parent renders
- handleClick is recreated
- Child renders again
Step 4: Optimize with useCallback
import { useCallback } from "react";
function Parent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log("Clicked");
}, []);
return (
<>
<button onClick={() => setCount(count + 1)}>
Count {count}
</button>
<Child onClick={handleClick} />
</>
);
}
Now the function reference stays the same.
If the child component is memoized using React.memo, it won't unnecessarily re-render.
useMemo vs useCallback
| useMemo | useCallback |
|---|---|
| Memoizes values | Memoizes functions |
| Prevents expensive recalculations | Prevents unnecessary function recreation |
| Returns computed value | Returns memoized function |
| Useful for filtering, sorting, calculations | Useful when passing callbacks to child components |
Which One Should You Use?
Use useMemo when:
- Filtering arrays
- Sorting data
- Expensive calculations
- Transforming API responses
Use useCallback when:
- Passing callbacks to child components
- Using
React.memo - Preventing unnecessary child re-renders
- Stable event handlers
Common Mistakes
❌ Using useMemo Everywhere
const value = useMemo(() => count + 1, [count]);
This calculation is trivial and doesn't need memoization.
❌ Forgetting Dependencies
useMemo(() => calculate(products), []);
Always include all required dependencies.
❌ Using useCallback Without React.memo
If child components aren't memoized, useCallback often provides little or no performance benefit.
Performance Tips
- âś… Measure performance before optimizing.
- âś… Use
useMemoonly for expensive computations. - âś… Use
useCallbackfor stable function references. - âś… Combine
React.memowithuseCallbackfor the best results. - ✅ Don't overuse memoization—simplicity is often better.
Conclusion
Both useMemo and useCallback are powerful optimization hooks, but they solve different problems.
-
useMemocaches computed values. -
useCallbackcaches functions.
Understanding the difference helps you write faster, cleaner, and more efficient React applications.
🎥 Watch the Complete Video Tutorial
Want to see everything implemented step by step?
📺 Watch the full tutorial here:
https://www.youtube.com/watch?v=lIVngCxky38
In the video, you'll learn:
- Complete implementation
- Real-world examples
- Performance optimization techniques
- Common mistakes to avoid
- Best practices for modern React applications
🚀 Learn React by Building a Complete Ecommerce Project
If you're serious about mastering React through real-world projects, check out our complete Ecommerce tutorial series.
You'll learn:
- React Fundamentals
- React Router
- Context API
- Authentication & Authorization
- Shopping Cart
- Product Filtering
- Stripe Payment Integration
- Firebase
- Express.js Backend
- Modern React Best Practices
🎥 Start the Ecommerce Playlist:
https://youtu.be/SdITjnl-zo8?si=IbA-E-Xe1ctJBEnY
Happy Coding! 🚀
Top comments (0)