Master performance optimization in React by understanding when and how to use useCallback and useMemo hooks effectively.
Prerequisites
Essential knowledge and skills you should have before starting
React's useCallback and useMemo hooks are powerful tools for performance optimization, but they're often misused. Let's explore when you actually need them and how to use them effectively.
Understanding useCallback
useCallback returns a memoized version of a callback function. It's useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders.
import { useCallback, useState } from 'react';
function ParentComponent() {
const [count, setCount] = useState(0);
const [todos, setTodos] = useState([]);
// Without useCallback, this function is recreated on every render
const addTodo = useCallback((text: string) => {
setTodos(prev => [...prev, { id: Date.now(), text }]);
}, []); // Empty dependency array means it never changes
return (
<>
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
<TodoList onAddTodo={addTodo} />
</>
);
} Understanding useMemo
useMemo memoizes the result of a computation. Use it for expensive calculations that don't need to run on every render.
import { useMemo } from 'react';
function DataTable({ data, filter }: Props) {
// Expensive computation - only recalculates when data or filter changes
const filteredData = useMemo(() => {
return data.filter(item =>
item.name.toLowerCase().includes(filter.toLowerCase())
);
}, [data, filter]);
return (
<table>
{filteredData.map(item => (
<tr key={item.id}>
<td>{item.name}</td>
</tr>
))}
</table>
);
} When NOT to Use Them
Don't use these hooks prematurely. Most of the time, React is fast enough without memoization. Only optimize when you have measurable performance issues. Overuse adds complexity and can actually hurt performance due to the overhead of comparison checks.
The Golden Rules
Use useCallback when passing callbacks to memoized child components. Use useMemo for expensive calculations with stable dependencies. Always measure before optimizing. And remember: premature optimization is the root of all evil.
Found this helpful?
I write about software engineering, architecture, and best practices. Check out more articles or get in touch.