React Performance Optimization: Fixing the Right Things
Most React performance problems aren't caused by missing memoization. Here's where to actually look.
React performance conversations often start and end with useMemo and useCallback. These are useful tools, but they're also frequently applied to problems they don't solve — and sometimes make worse by adding memoization overhead to components that re-render infrequently anyway.
The first place to look for performance problems is unnecessary re-renders. Use React DevTools Profiler to record an interaction and see which components render, why they render, and how long rendering takes. A component re-rendering because its parent re-rendered isn't necessarily a problem — it's only a problem if the render is expensive or triggers further unnecessary work.
Context is a common performance foothole. Every component that consumes a context value re-renders when any value in that context changes. The fix is to split contexts by update frequency — keep high-frequency state (e.g., scroll position) separate from low-frequency state (e.g., theme preference). Alternatively, use a state management library that supports selective subscriptions.
Large list rendering is another common issue. If you're rendering hundreds or thousands of items, virtual lists (react-window, TanStack Virtual) are the right tool — they render only the items currently in the viewport. Even well-memoized components add up when there are thousands of them in the DOM.
Bundle size matters for initial load performance. Use next/bundle-analyzer or webpack-bundle-analyzer to visualize what's in your bundles. Large dependencies that are only used in a few places should be dynamically imported. Libraries like Lodash or Moment.js are common culprits — they import entire libraries when you need one function.
The pattern that prevents most performance problems: keep component trees shallow, colocate state close to where it's used, and measure before optimizing. Most perceived performance issues are network latency, not React rendering.