If your React app loads in over three seconds on mobile, the reasons are usually the same seven things. None of them are inherent to React itself; all of them are decisions that can be reversed. This guide walks through them in order of impact.

The honest summary: React is not slow. Slow React apps are slow because of bundle size, hydration overhead, sequential data fetching, unoptimised images, and render loops that the developer did not notice in development. Fix those, and the same app moves from a 4-second LCP to under 1.5 seconds. We have done this engagement many times. The seven fixes below are exactly what we change, in the order we change them.

How to measure first

Three tools matter: Chrome DevTools Performance tab (for understanding where time goes in render and JS execution), Lighthouse on mobile throttling (for the headline scores and Core Web Vitals), and React Profiler (for finding components that re-render unnecessarily). Record the baseline LCP, CLS, INP, TTFB, and the main bundle size. These are the numbers you will compare against after each fix.

Fix 1 — Audit the bundle

The single biggest performance lever on a typical React app is bundle size. A standard Create React App with a few popular libraries (Material UI, lodash, moment, three.js) easily reaches 600 to 900 KB of JavaScript on first load. The browser has to download, parse, and execute every byte before the user sees anything.

The fix is an audit using webpack-bundle-analyzer or Vite's rollup-plugin-visualizer. Common findings: moment.js (replace with date-fns or native Intl), lodash (replace with native methods or import per-function), Material UI v4 or older (upgrade to v5 with proper tree-shaking), three.js (lazy-load only on pages that use it), heavy icon libraries (import only what you use). Typical audits cut the main bundle 40 to 60% before any other work.

Fix 2 — Code-split per route

Most React apps load every route's code into the initial bundle. Even if the user only visits the homepage, they download the JavaScript for the dashboard, the settings page, the admin section, and every other route in the app. This is unnecessary.

The fix is React.lazy + Suspense (vanilla React) or built-in route-level code splitting (Next.js, Remix). Each route becomes its own bundle, loaded only when the user navigates to it. The homepage typically drops from 600 KB to 80 to 150 KB. The other routes load lazily on demand, with a brief loading state.

Fix 3 — Optimise images properly

Images are the largest payload on most React app pages. A typical hero image uploaded straight from a designer's laptop is 3 to 8 MB. The same image properly optimised is 80 to 200 KB.

The fix is three steps: convert to AVIF or WebP (both compress significantly better than PNG / JPEG), use responsive srcset with multiple resolutions for different viewport sizes, lazy-load offscreen images with the native loading=”lazy” attribute or react-intersection-observer. For Next.js, the built-in next/image component handles most of this automatically. For vanilla React, libraries like react-lazy-load-image-component or hand-rolled IntersectionObserver work.

The hero image specifically should be preloaded with a link rel=preload in the document head — this often moves LCP from 2.8 to 1.0 seconds by itself.

React is not slow. Slow React apps are slow because of bundle size, hydration overhead, sequential data fetching, and decisions the developer did not notice.

Fix 4 — Eliminate hydration mismatches and unnecessary client-side work

Hydration is the process where Next.js / Remix / Astro / Gatsby take server-rendered HTML and attach React event handlers to make it interactive. When hydration fails (mismatch between server-rendered HTML and client-rendered React), the whole tree re-renders, often doubling the work the browser has to do.

Common causes: code that runs differently on server and client (Date.now(), Math.random(), window references in render), components that load data conditionally based on session state, third-party libraries that mutate the DOM directly. The React DevTools console will surface hydration warnings; treat every one as a real bug, not a warning to ignore.

For applications using Next.js App Router, the deeper fix is to use Server Components for content that does not need interactivity. A typical product page on a SaaS marketing site uses Server Components for 70% of the content (header, footer, hero, feature blocks, footer) and Client Components only where interactivity is needed (form, search, modals). Total client-side JavaScript drops dramatically.

Fix 5 — Fix the data-fetching waterfall

A typical slow React app has a fetch waterfall: the page mounts, useEffect fires, an API call returns, then a child component mounts based on that data, fires its own useEffect, another API call returns, then a grandchild does the same. The user sees a loading state for 2 to 4 seconds while three sequential round-trips complete.

The fix has three parts: parallelise the API calls that can run in parallel (Promise.all, or React Query's useQueries), move data fetching to the server using Server Components or route loaders, prefetch data based on hover or focus before the user actually clicks. For Next.js App Router, this means structuring layouts so Server Components fetch data in parallel at the layout level rather than serially in child components.

Fix 6 — Optimise fonts and third-party scripts

Custom fonts cause flash-of-invisible-text (FOIT) or flash-of-unstyled-text (FOUT), both of which hurt LCP. The fix is font-display: swap in the @font-face declaration, preloading the critical font file with link rel=preload, and using next/font (or similar) to inline the font CSS and self-host the font files.

Third-party scripts — analytics, marketing pixels, chat widgets, customer-data platforms — are usually the largest source of main-thread blocking on a production React app. Audit every third-party script; defer everything that does not need to run before first paint; load chat widgets and survey tools only after user interaction. Google Tag Manager alone often loads 200 to 400 KB of JavaScript before the user sees anything.

Fix 7 — Profile and fix render performance

The last fix is for the long tail: components that re-render unnecessarily, computations that should be memoised, lists that should use React.memo or virtualisation. Use React Profiler to record an interaction and look for components that render dozens of times when they should render once.

Common patterns: context providers that change shape on every render (causing every consumer to re-render), inline object/function props that break referential equality, useState updates that should be useReducer, large lists rendered without windowing (react-window or react-virtuoso). Each fix shaves 10 to 50 ms off interaction time; collectively they move INP from 300 ms (failing) to under 100 ms (good).

What good looks like after the seven fixes

A well-tuned React app in 2026 hits these numbers:

LCP under 1.5 seconds on real mobile devices and networks.

CLS under 0.05. Effectively no layout shift if images have explicit dimensions and fonts are preloaded.

INP under 100 ms. Interactions feel instant on mid-range mobile hardware.

Initial JavaScript under 150 KB gzipped on the homepage. Route-split bundles for other pages.

Lighthouse mobile score above 90 on every page. Stretch goal: above 95.

These are the numbers we ship on every React build at Dream Steps Technologies. Performance is not optional; it is part of the build.

If you do not want to do this yourself

Performance work on a React codebase is detailed engineering. We offer a React performance audit as a fixed-scope engagement: we measure the current Core Web Vitals, profile bundle size and render performance, identify the seven highest-impact fixes for your app specifically, and either hand you the report or implement them ourselves. Most clients see LCP halve in the first two weeks.

Common questions

How much will fixing all seven things improve my React app?

On a typical slow React app (4-second LCP, PageSpeed mobile score 30-50), all seven fixes together usually move LCP under 1.5 seconds and the mobile Lighthouse score above 90. Specific gains depend on starting state: apps with heavy bundles see the largest gains from the bundle audit and code splitting; apps with hydration mismatches see the largest gains from the Server Components migration; apps with API waterfalls see the largest gains from parallelisation and server-side fetching.

Do I have to migrate to Next.js to get fast React performance?

No. Vanilla React with Vite can be very fast if bundle size, code splitting, and image optimisation are done well. The performance gap is largest on first-load LCP for content-driven pages (where SSR helps) and closes on subsequent navigations once the app is hydrated. Most of the seven fixes apply to vanilla React and Next.js equally; the framework choice determines whether you get SSR for free or build it yourself.

How long does a React performance engagement take?

Audit alone is typically 3 to 5 working days. Implementation depends on the seven fixes the audit prioritises and the starting state. A typical engagement is 2 to 4 weeks of part-time work, often delivered while the existing app stays live and changes are tested on staging first. For complex apps with significant refactoring (App Router migration, Server Components conversion), expect 4 to 8 weeks.

What if my app is built with create-react-app — is that the problem?

Create React App is no longer actively maintained as of 2023 and is missing modern build optimisations. We usually recommend migrating to Vite (for vanilla React apps) or to Next.js (for content-driven apps) as part of any performance engagement. Vite migration is straightforward and takes 1 to 2 weeks for most apps. The performance lift from the migration alone is typically 20 to 40% before any other work.

Does React performance affect SEO?

Yes, in two ways. Core Web Vitals are direct Google ranking signals — sites that pass them rank visibly higher than identical sites that fail. Fast sites also have lower bounce rates and higher engagement, which feed back into ranking signals. For content-driven React apps (which should ideally be Next.js or similar SSR framework anyway), the SEO uplift from performance work is typically 15 to 40% organic traffic in the first 90 days.

Want a free React performance audit?

Send us your repo or a deployed URL. We will send back a 2-page audit showing your current Core Web Vitals, bundle composition, and the seven highest-impact fixes for your app specifically.


Request a performance audit