Memoization
Memoization is a technique to cache computed values and skip unnecessary re-renders, improving performance by avoiding redundant work.
React.memo
React.memo is a higher-order component that prevents re-renders when props haven’t changed. It performs a shallow comparison of props (see ReactMemo.js:12).
Implementation
From ReactMemo.js:12-29, React.memo wraps a component and optionally accepts a custom comparison function:
Basic Usage
Before: Unnecessary Re-renders
After: Optimized with memo
Result: When clicking the button, only the parent re-renders. UserCard stays unchanged because its props haven’t changed.
Custom Comparison Function
By default, React.memo does shallow comparison. Provide a custom comparison for complex scenarios:
The custom comparison function works opposite to shouldComponentUpdate. Return true to skip rendering, false to re-render.
Display Name Handling
From ReactMemo.js:31-56, React automatically handles display names for debugging:
useMemo
useMemo caches expensive calculations, recomputing only when dependencies change (see ReactHooks.js:143).
Implementation
From ReactHooks.js:143-149:
Basic Usage
Before: Re-computing on Every Render
After: Optimized with useMemo
Result: The expensive calculation only runs when data or sortOrder actually changes, not on every render.
Referential Equality
Use useMemo to maintain stable object references:
useCallback
useCallback memoizes functions, ensuring the same function reference across renders (see ReactHooks.js:135).
Implementation
From ReactHooks.js:135-141:
Basic Usage
Before: New Function on Every Render
After: Stable Function Reference
Result: SearchResults doesn’t re-render when typing in the input field because handleResultClick maintains the same reference.
useCallback vs useMemo
useCallback is a shorthand for useMemo that returns a function:
When to Memoize
Memoization is useful when:
- Component renders frequently with the same props
- Component has expensive calculations or rendering
- Passing callbacks to memoized child components
- Working with large lists or complex data structures
- Preventing effect re-runs with stable dependencies
Good Candidates for Memoization
Poor Candidates for Memoization
Avoid premature optimization! Memoization has costs:
- Memory overhead to store cached values
- Comparison overhead on every render
- Code complexity and maintenance burden
Only memoize when profiling shows a real performance problem. In many cases, React’s default behavior is fast enough.
Memoization Trade-offs
Memory vs Speed
Comparison Overhead
Dependency Management
Use the eslint-plugin-react-hooks ESLint plugin to catch missing dependencies. It warns when your dependency array might be incorrect.
Real-World Patterns
Combining Memoization Techniques
From ReactProfiler-test.internal.js:204, here’s a pattern combining React.memo with useMemo:
Memoizing Context Values
Optimizing Event Handlers
Debugging Memoization
Check if memoization works:
React DevTools Profiler shows why components re-rendered:
- Open React DevTools
- Go to Profiler tab
- Record a session
- Click on a component in the flame graph
- Check “Why did this render?” to see which props changed