Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Lazy Loading and Code Splitting in React

Lazy Loading in React

~10 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

To wrap up Phase 4: how to make sure the browser doesn't have to download the code for EVERY single page before the app even starts – only the code for the page the user is actually looking at right now.

The problem: an ever-growing bundle

Without special measures, Vite packs the ENTIRE JavaScript code of our app – ProductListPage, ProductDetailPage, ReviewsPage, LoginPage, AccountPage, and everything they import – into ONE single file (the "bundle"), which the browser must download in full on the very first page visit. For a small app like ours that's not a problem, but for real, large applications with dozens of pages, the bundle can grow to several megabytes, and the initial load time can become noticeably slow.

The solution: React.lazy() + Suspense

React.lazy() turns a regular import into a DEFERRED import – the code for that page only gets downloaded once it's actually needed ("code splitting"). Since downloading takes time, React needs something to display in the meantime – that's what <Suspense> is for.

Updating App.jsx: lazy-loading less-used pages

We selectively lazy-load pages that not every visitor needs (login, account, reviews) – the home page ProductListPage and the product detail page stay as regular imports, since they're the most-used pages:

src/App.jsx
import { lazy, Suspense } from 'react';
import { Routes, Route } from 'react-router-dom';
import { useAuth } from './context/AuthContext';
import { useDocumentTitle } from './hooks/useDocumentTitle';
import ProductListPage from './pages/ProductListPage';
import ProductDetailPage from './pages/ProductDetailPage';
import ProtectedRoute from './components/ProtectedRoute';

const ReviewsPage = lazy(() => import('./pages/ReviewsPage'));
const LoginPage = lazy(() => import('./pages/LoginPage'));
const AccountPage = lazy(() => import('./pages/AccountPage'));

function App() {
  const { user, login, logout } = useAuth();
  useDocumentTitle('Product Catalog');

  return (
    <div className="app">
      <header className="app-header">
        <h1>Product Catalog</h1>
        {user ? (
          <p>Logged in as {user.username} <button onClick={logout}>Log out</button></p>
        ) : (
          <button onClick={() => login('Jane Doe')}>Log in</button>
        )}
      </header>

      <Suspense fallback={<p>Loading page...</p>}>
        <Routes>
          <Route path="/" element={<ProductListPage />} />
          <Route path="/products/:sku" element={<ProductDetailPage />}>
            <Route path="reviews" element={<ReviewsPage />} />
          </Route>
          <Route path="/login" element={<LoginPage />} />
          <Route
            path="/account"
            element={
              <ProtectedRoute>
                <AccountPage />
              </ProtectedRoute>
            }
          />
        </Routes>
      </Suspense>
    </div>
  );
}

export default App;

Two changes work together: const ReviewsPage = lazy(() => import('./pages/ReviewsPage')) instead of a regular import ReviewsPage from './pages/ReviewsPage' at the top of the file, AND <Suspense fallback={{...}}> around <Routes>, which shows what should be visible while loading.

Vanilla JS/HTMLReact
All <script> tags get downloaded immediately when the page loadslazy() pages only get downloaded once that route is actually visited
No built-in concept for a "loading state while downloading more"<Suspense fallback={{...}}> automatically shows a loading state

Open the "Network" tab in your browser's dev tools, load the home page, then navigate to /login: you'll see a NEW, separate JavaScript file being downloaded, exactly at that moment – before that, its code simply wasn't part of the downloaded bundle. That wraps up Phase 4 (Routing).

Tipp: Rule of thumb: lazy-load pages that (a) are rarely visited (login, account, settings) or (b) bring in especially large dependencies (e.g. a charting or PDF library). Keeping the home page and other frequently visited core pages as regular imports usually remains the better choice, since the extra loading step itself also costs time.