Field note / react

publishedupdated 2026-05-04#react#performance#memoization#virtualization#profiler

React Performance Patterns

Profiling, memoization, context splitting, list virtualization, and the React performance fixes I trust more than guesswork.

TL;DR

  • I profile first and optimize second.
  • The biggest wins usually come from reducing unnecessary work, not from clever micro-optimizations.
  • React.memo, useMemo, and useCallback only help when they protect a real expensive boundary or stabilize a meaningful contract.
  • Long lists, chatty context providers, and expensive render paths usually cause more pain than React itself.

Context

When a React app feels slow, my first instinct is not to add memoization everywhere. I want to know whether the problem is too many renders, too much work per render, too much DOM on screen, or too much work happening on the main thread during input.

The Approach

My usual checklist:

  1. use the React Profiler
  2. find repeated renders
  3. find expensive renders
  4. check state placement
  5. virtualize large lists when needed
const Row = React.memo(function Row({ item }) {
  return <div>{item.name}</div>
})

I only keep React.memo if:

  • props are stable enough for it to matter
  • the child is expensive enough to justify the comparison

If the issue is a long list, virtualization is usually a bigger win than hook-level memo tuning.

I also watch for these recurring patterns:

  • context providers that change value every render
  • inline object or function props crossing many memo boundaries
  • expensive filtering or sorting inside render
  • synchronous work inside input handlers that should be deferred or moved

If an interaction-heavy view still struggles after structural cleanup, I start thinking about:

  • useTransition
  • useDeferredValue
  • web workers for heavy computation
  • smarter server/client boundary choices

Trade-offs

  • Memoization can help, but it adds cognitive load and sometimes hides the real architecture problem.
  • Virtualization improves throughput, but it makes layout and measurement more complex.
  • Splitting context reduces noisy re-renders, but it can make the provider tree more verbose.
  • Deferred rendering patterns help responsiveness, but they also make update timing less immediate and sometimes harder to debug.

References