Skip to content
ReactField

TopicsIntermediate

React Performance & Optimization

React performance hub for production apps: separate load vs runtime, pick LCP or INP, then open bundle, waterfall, re-render, or JS deep dives.

Mohamed ElshahawyPublished Apr 2026Updated Oct 2026
6 min read

What you'll learn

  • Separate loading performance from runtime performance
  • Focus paths for slow LCP, janky runtime, measurement and ship checklists
  • Match hangups to bundle, re-renders, waterfalls, JS cost or layout shift
  • Measure with Web Vitals and the React Profiler before optimizing

Performance in React apps falls into two buckets:

  1. Loading performance - how fast code and assets arrive (mostly delivery)
  2. Runtime performance - how smoothly the app responds after load (mostly React and JS on the main thread)

This page is the performance cluster hub. Use the focus picker when you know the symptom. Use the hangup matcher when you need the deepest sibling article. Then measure, change one thing, and re-measure.

Four doors labelled LCP, runtime jank, measure first and ship checklist leading into a toolbox
Pick a door before collecting every optimization tip.

How to use this hub

  1. Name the bucket. Is the user waiting on first paint, or on a click after the page is open?
  2. Pick one metric. LCP for load. INP for interaction. Profiler self-time for component work. CLS when the page jumps.
  3. Open one deeper article. Bundle, re-renders, waterfalls or JS patterns. Do not do all four at once.
  4. Re-measure. If the number did not move, revert and try the next hangup.

Pick a performance focus

Try it: performance focus

Pick what hurts. You get an ordered focus, why it fits, and a first-week plan.

Focus

Your focus

Treat load as a delivery problem first

Slow Largest Contentful Paint is usually bytes, images and critical path, not memo. Shrink what you ship, then improve how you render HTML.

  1. Web Vitals

    Know which vital you are chasing.

  2. PageSpeed Insights

    Field and lab signals for the URL.

  3. Bundle Size Optimization

    Code splitting and unused JS.

  4. React Rendering Strategies

    SSR and streaming when HTML arrives late.

First week

Run Lighthouse or PageSpeed on the slow URL. Cut one heavy route chunk and one oversized image. Re-check LCP.

Tip: write down one metric before you open a deep dive. LCP for load, INP for clicks, Profiler self-time for component work.

Checkpoint

LCP is slow and the route ships a large unused library. What first?

Match a performance hangup

Hangup chips connected to article cards for bundle size, re-renders, waterfalls and JS patterns
Name the hangup, then open the matching deep dive.

Try it: match a performance hangup

Choose the hangup you see. The matcher points to the deepest article for that job.

Hangup

The hangup

LCP or TTI is slow and Coverage or the bundle analyzer shows a heavy route chunk.

Start here

Bundle Size Optimization

Load problems are usually bytes and critical path. Split routes and drop unused libraries before memoizing components.

Also consider

Hidden Side of Frontend Deployments

Lazy chunks must still resolve for open tabs after deploy.

Related: Lazy chunks after deploy

Tip: Related points at a sibling topic, not the same article as Start here. Open one deep dive, then come back.

Key takeaway

Name the bucket (load vs runtime) before picking a library or a memo.

Loading vs runtime

Left, labelled Loading: a browser window with a progress bar and an hourglass. Right, labelled Runtime: the loaded page responding to a click with a speed gauge
Loading is how fast the app becomes usable. Runtime is how smoothly it responds once it is open.

Loading performance measures how fast content becomes usable. Core Web Vitals for this lane include Largest Contentful Paint (LCP) and Cumulative Layout Shift (CLS). Older guides mentioned First Input Delay (FID); for interaction responsiveness, use Interaction to Next Paint (INP) instead.

Runtime performance measures how smooth the app feels after load: frame rate, long tasks, memory and how often React commits large trees for small updates.

A funnel from one metric chip into four deep-dive article cards for bundle, re-renders, waterfalls and JS patterns
One metric, one deep dive. Come back to the hub before opening the next door.

The key habit

Name the bucket and one metric before you open a deep dive. LCP for load, INP for clicks, Profiler self-time for component work.

Load lane: measure and optimize

Which tool for which signal

ToolBest forInsight
PageSpeed Insights (opens in a new tab)Field plus lab signal on a public URLStart here when you need a shared number for LCP, INP or CLS
Lighthouse (opens in a new tab)Repeatable lab baseline in CI or locallyGood for regressions on a changed route; weaker as a substitute for real-user data
WebPageTest (opens in a new tab)Waterfall detail and filmstripUse when you need to see which request blocked first paint
Web Vitals (opens in a new tab) / INP (opens in a new tab)Definitions and thresholdsRead these when the team argues about which metric counts

Insight: lab scores without a production-like device and network lie. Pair Lighthouse with at least one field view when stakeholders ask "is it slow for users?"

Insight: if Network is a staircase of independent requests, leave the memo debate and open Eliminating Async Waterfalls.

Optimizing load

Send as little code and media as possible, then improve how HTML arrives.

  • Compress responses (gzip or Brotli) and optimize images and video
    Insight: LCP is often a hero image or font, not a missing useMemo.

  • Lazy-load below-the-fold media
    Insight: reserve space (width/height or aspect-ratio) or CLS climbs while LCP looks fine.

  • Build and minify assets; split routes so unused screens stay out of the first load
    Insight: route splits beat wrapping the home page in memo. See Bundle Size Optimization.

  • Use React.lazy and Suspense carefully
    Insight: lazy chunks must stay available after deploy for open tabs (The Hidden Side of Frontend Deployments).

  • SSR and streaming can improve first paint when the HTML path is the bottleneck
    Insight: if the browser waits on JS before any meaningful HTML, open React Rendering Strategies.

Runtime lane: measure and optimize

A person holding a magnifying glass over a flame chart where one long orange bar stands out, with a wrench waiting nearby
Profile first to find the bar that actually matters, then reach for the wrench.

Modern React is fast by default. Do not optimize until a component or interaction is slow in a production-like scenario.

  1. Do not optimize too soon
  2. Know what to measure

Decision tree

When the Profiler or Chrome Performance panel shows pain after load, pick the branch:

  1. Slow render (high self-time inside one component) → JavaScript Performance Patterns. Offload true background work to Web Workers when it should not block paint.
  2. Too many re-renders (wide commit trees for a small state change) → Stop Unnecessary Re-renders.
  3. Slow data (Network stair-steps or mount-time fetch chains) → Eliminating Async Waterfalls.


Helpful measurement links:

Memoization and list virtualization help different problems:

Checkpoint

Which metric should you use today for interaction responsiveness?

UX performance practices

  • Throttle or debounce high-frequency DOM updates; humans cannot usefully process hundreds of visual updates per second
  • Read how fast of an interaction is too fast (opens in a new tab)
  • For loading states under about 400ms, either skip the spinner or keep it visible long enough that it does not flicker

Performance anti-patterns

These mistakes do not need another hangup chip. Avoid them on purpose:

  • Memo as an LCP fix. React.memo does not shrink the network. Cut bytes and media first.
  • Clinging to FID docs. Teach INP for interaction responsiveness; keep FID only as a quiz distractor or history note.
  • Spinner flicker under 400ms. A flash of pending UI feels slower than no spinner at all.
  • Experimental VDOM as default. Treat niche renderers as research. Measure against your own product before adopting them as architecture.

Performance checklist

  • I know whether the pain is load or runtime
  • I tracked LCP, INP or CLS (not FID) for the critical flow
  • Bundle size is reviewed for changed routes
  • Re-renders and JS cost were profiled before memo sprawl
  • Async waterfalls were checked in Network
  • A change was re-measured or reverted

Further reading

Conclusion

Performance work is triage, not a library shopping trip. Separate load from runtime, pick one metric, open one deep dive, and prove the number moved. If it did not move, undo the complexity and try the next hangup.

The hub stays useful when teams return with a new symptom: re-run the focus picker, open one sibling article, and leave the rest alone until the first metric improves.

The key takeaway

Measure the bucket that hurts, then fix that bucket. Memo is not a load-time strategy.

Check your understanding

Test yourself6 questionsQuestion 1 of 6

LCP is slow and a route ships a large unused library. What first?

Decision framework

SymptomFirst move
Slow LCPBundle and media (Bundle Size)
Slow click / INPProfiler, then re-renders or JS cost
Stair-step networkAsync waterfalls
Layout jumpCLS: reserve space, avoid late inserts
Post-deploy ChunkLoadErrorDeployments

When not to optimize

  • You have no metric and no user complaint
  • You are about to memoize “everywhere” without a profile

Checklist

  • Named the bucket: load vs runtime
  • Picked one metric
  • Changed one thing and re-measured

Recap

What to remember from this article

Sections read

0

Questions

0

none answered yet

Quiz

0

not taken yet

Up next: Why Parent State Re-renders Children · 8 min

Continue