← All posts

React Performance: A Practical Checklist

React is fast by default — until it isn't. Most performance problems aren't React's fault; they come from doing more work than necessary. Here's the checklist I run through when an app starts feeling sluggish.

1. Measure before you optimize

Open the React Profiler and record an interaction. You'll usually find that one or two components are re-rendering far more than they should. Don't guess — let the flame graph point you at the problem.

2. Stop unnecessary re-renders

A component re-renders when its state or props change. Two common culprits create new references on every render:

  • Inline object/array literals passed as props
  • Inline functions passed to memoized children

Stabilize them with useMemo and useCallback, and wrap pure presentational components in React.memo:

const handleSelect = useCallback((id) => {
  setSelected(id);
}, []);

const sorted = useMemo(
  () => items.slice().sort(byName),
  [items]
);

3. Don't lift state higher than it needs to be

State that lives too high re-renders the whole tree on every keystroke. Keep state as local as possible, and split large contexts so unrelated consumers don't re-render together.

4. Virtualize long lists

Rendering 10,000 rows kills performance even if each row is cheap. Render only what's visible with a windowing library like react-window. The DOM stays small and scrolling stays smooth.

5. Trim the bundle

A fast render doesn't help if the user waited five seconds for the JavaScript to download. Code-split routes with React.lazy and Suspense, audit your dependencies, and ship less:

const Dashboard = React.lazy(() => import('./Dashboard'));

<Suspense fallback={<Spinner />}>
  <Dashboard />
</Suspense>
The goal isn't to memoize everything — it's to do less work. Measure, fix the biggest offender, measure again.

Wrapping up

Profile first, eliminate wasted renders, keep state local, virtualize big lists, and ship a smaller bundle. Do those five things and the vast majority of React performance issues simply disappear.

← Back to all posts