Performance & React DevTools
Profile renders, fix slow components, virtualise long lists, split bundles and measure Web Vitals.
A fast app feels professional; a sluggish one drives users away. The good news is React apps are usually fast enough by default, and when they're not, the problem is almost always one of a handful of causes. This lesson shows you how to find problems with React DevTools and browser tools, and how to fix the common ones.
The golden rule: measure first#
Don't optimise based on hunches. The workflow is:
- Notice something slow (typing lags, a page takes ages to load).
- Measure with tools to find the actual cause.
- Fix that one thing.
- Measure again to confirm it helped.
Always measure a production build. Development mode is deliberately slower (extra checks, Strict Mode double-renders):
React Developer Tools#
Install the React Developer Tools extension for Chrome, Firefox or Edge. It adds two tabs to your browser's DevTools.
⚛️ Components
- Browse the component tree, just like the Elements panel shows the DOM.
- Select a component to see and edit its props, state and hooks live.
- See which component rendered a DOM element, and its owner chain ("rendered by").
- Click the eye icon to inspect the matching DOM node; click
<>to jump to the source.
In the settings (⚙️), turn on "Highlight updates when components render". Now every re-render flashes an outline on the page. Type into a search box: if the whole page flashes, you've found unnecessary re-renders.
⚛️ Profiler
- Open the Profiler tab and press Record (●).
- Perform the slow interaction (type, click, switch tabs).
- Press Stop.
You'll see each commit (a batch of updates applied to the DOM) as a bar. Select one to see:
- Flame graph — the component tree for that commit; width and colour show render time. Grey components didn't render.
- Ranked chart — components sorted by how long they took.
- "Why did this render?" — enable "Record why each component rendered while profiling" in settings to see "Props changed: (onSelect)", "State changed", "Parent component rendered" and so on.
Typical findings: a component re-rendering because a parent passed a new inline function, or one expensive component taking 80% of the commit.
The browser Performance panel#
Chrome DevTools' Performance panel records everything the browser does: JavaScript, layout, painting and network. React 19.2 adds custom tracks here — a Scheduler track showing what React is working on and at which priority, and a Components track showing component render and effect timings — so you can see React work next to browser work. Use the CPU throttling option (e.g. "4× slowdown") to simulate a cheaper phone.
Measuring in code: <Profiler>#
React's <Profiler> component reports render timings programmatically:
phaseis"mount","update"or"nested-update".actualDurationis the time spent rendering this commit;baseDurationestimates the cost without any memoisation.
Profiling adds overhead and is disabled in standard production builds, so use it for investigation, not permanently.
Common problems and fixes#
1. Too many re-renders
Symptom: typing in one input re-renders the whole page.
Fixes, in order of preference:
- Move state down into the component that actually uses it.
- Pass children so wrappers with state don't re-render their content.
- Split contexts so updates only reach components that care.
- Select narrowly from stores (
useStore((s) => s.count)). - Memoise (
memo,useMemo,useCallback) — or enable the React Compiler to do it automatically.
2. Expensive rendering
Symptom: one component takes many milliseconds every render.
Fixes: useMemo for the calculation, useDeferredValue so typing stays responsive, or move the work to the server.
3. Huge lists
Rendering thousands of DOM nodes is slow no matter how clever your React code is. Virtualise: only render rows in (or near) the viewport.
10,000 rows, but only ~15 DOM elements at a time.
4. Large JavaScript bundles
Symptom: the first load is slow, especially on mobile.
- Code-split routes and heavy features with
lazy(see Suspense & lazy loading). - Check what's in your bundle.
npm run buildprints chunk sizes; a visualiser such asnpx vite-bundle-visualizershows which packages take up space. - Prefer smaller dependencies and import only what you use (
import debounce from "lodash-es/debounce"rather than the whole library).
That warning is your cue to split.
5. Slow images and fonts
- Set
widthandheighton images to avoid layout shift. - Use
loading="lazy"for images below the fold, modern formats (WebP/AVIF) and appropriately sized files. - Preload critical fonts and use
font-display: swap.
6. Request waterfalls
A parent fetches, renders, then its child starts fetching — each request waits for the previous one. Start requests in parallel (Promise.all), fetch in route loaders, or prefetch with TanStack Query.
Core Web Vitals#
Google's Core Web Vitals measure real user experience:
Check them with Lighthouse (in Chrome DevTools) or collect them from real users with the web-vitals package:
In a real app, send these to your analytics instead of logging them.
A performance checklist#
- Profiled a production build, with CPU throttling
- No components re-render on every keystroke without reason
- Long lists are virtualised or paginated
- Routes and heavy features are lazy-loaded
- Images are sized, compressed and lazy-loaded
- Data requests run in parallel and are cached
- Lighthouse scores are green for LCP, INP and CLS
Common mistakes#
- Profiling in development mode and chasing problems that don't exist in production.
- Adding
useMemoeverywhere without measuring. - Ignoring bundle size because "it's fast on my laptop".
- Optimising React when the real bottleneck is a slow API or a 5 MB image.
- Leaving the "Highlight updates" setting on and panicking — a flash means a render happened, not that it was slow.
What's next#
Fast is good; usable by everyone is essential. Next: accessibility in React.
Check your understanding
Quick quiz
1.Why should you measure performance with a production build?
2.What does the React DevTools Profiler show?
3.A list of 10,000 rows makes scrolling janky. What's the most effective fix?
Finished reading?
Mark this lesson complete to track your progress.