Mastering Performance: useMemo and useCallback
In React, every state change causes a component to re-render. While this is usually fine, it can become a bottleneck when performing heavy calculations or passing props to child components. useMemo and useCallback provide a way to "remember" previous results and prevent unnecessary work.
1. useMemo: Memoizing Values
useMemo caches the result of a calculation. It only re-calculates the value if one of its dependencies changes.
Best for: Filtering or sorting large lists, or performing expensive mathematical operations.
const filteredList = useMemo(() => {
console.log('Filtering large list...');
return largeList.filter(item => item.name.includes(searchQuery));
}, [searchQuery, largeList]); // Only re-runs if searchQuery or largeList changes2. useCallback: Memoizing Functions
useCallback caches the function definition itself. This is crucial when passing functions as props to child components that are wrapped in React.memo.
Best for: Preventing child components from re-rendering when the parent re-renders.
const addToCart = useCallback((item) => {
setCart(prev => [...prev, item]);
}, []); // Function reference remains the same across rendersEssential Best Practices & Pitfalls
Avoid “Over-optimization”: Don’t wrap every function or value in these hooks. Memoization itself has a memory cost. Only use them for expensive operations or to break unnecessary render chains.
Fix Dependency Arrays: A common mistake is leaving variables out of the dependency array, which leads to “stale” data.
Use Functional State Updates: To minimize dependencies in
useCallback, use the functional form of state setters (e.g.,setCart(prev => ...)). This allows you to omit the state variable from the dependency array.React.memoContext:useCallbackis only effective if the receiving child component is wrapped inReact.memo. Otherwise, the child will re-render anyway.
Conclusion
useMemo and useCallback are your primary tools for preventing performance issues in complex React applications. By understanding that useMemo caches results and useCallback caches references, you can write applications that only do the work they absolutely need to do. Always remember: measure performance before optimizing to avoid adding unnecessary complexity to your code.