Skip to main content

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:

Using React DevTools

React DevTools Profiler shows why components re-rendered:
  1. Open React DevTools
  2. Go to Profiler tab
  3. Record a session
  4. Click on a component in the flame graph
  5. Check “Why did this render?” to see which props changed