When to Use useCallback and useMemo
These hooks are for optimization, not decoration. Here's when they actually help.
The Short Answer
**Most of the time, you don't need them.**
React is fast. Re-renders are usually fine. Premature optimization makes code harder to read.
What They Do
useCallback
Memoizes a function so it doesn't get recreated on every render:
// Without useCallback: new function every render
const handleClick = () => setCount(c => c + 1);
// With useCallback: same function reference
const handleClick = useCallback(() => {
setCount(c => c + 1);
}, []); // dependencies
useMemo
Memoizes a computed value:
// Without useMemo: computed every render
const expensiveResult = calculateExpensiveThing(data);
// With useMemo: only recomputed when data changes
const expensiveResult = useMemo(() => {
return calculateExpensiveThing(data);
}, [data]);
When They Help
useCallback: Passing to memoized children
const Parent = () => {
const handleClick = useCallback(() => {
doSomething();
}, []);
// Without useCallback, MemoizedChild re-renders every time
return <MemoizedChild onClick={handleClick} />;
};
const MemoizedChild = React.memo(({ onClick }) => {
return <button onClick={onClick}>Click</button>;
});
If the child isn't memoized, useCallback does nothing useful.
useMemo: Expensive calculations
const SearchResults = ({ items, query }) => {
const filteredItems = useMemo(() => {
return items.filter(item => {
// Expensive filtering logic
return complexMatch(item, query);
});
}, [items, query]);
return <List items={filteredItems} />;
};
Only worth it if the calculation is actually expensive and the dependencies change less often than the component renders.
When They DON'T Help
Simple values
// ❌ Overkill
const name = useMemo(() => `${first} ${last}`, [first, last]);
// ✅ Just compute it
const name = `${first} ${last}`;
Functions not passed to children
// ❌ Pointless
const handleSubmit = useCallback(() => {
api.submit(data);
}, [data]);
return <button onClick={handleSubmit}>Submit</button>;
Regular button doesn't care if the function reference changes.
Profile First
Before adding memoization:
1. Is there actually a performance problem? 2. Use React DevTools Profiler 3. Find the slow component 4. Then optimize specifically
Don't guess. Measure.
The Rule
- Start without memoization
- Notice a performance issue
- Profile to identify the cause
- Add memoization where it helps
- Verify it helped
Readability matters more than micro-optimizations.