← Back to Chapters

Lazy Loading Routes

⚛️ Lazy Loading Routes

? Quick Overview

Lazy loading routes in React improves performance by loading page components only when the user navigates to them, reducing the initial JavaScript bundle size.

? Key Concepts

  • React.lazy() for dynamic imports
  • Suspense for fallback UI
  • Route-based code splitting
  • Improved load time and UX

⚛️ Introduction

Lazy loading allows React to load components only when needed — improving performance and reducing initial load time.

In React Router v6+, lazy loading routes can be achieved using React’s built-in React.lazy() and <Suspense> components.

? Without Lazy Loading

Normally, all components are imported at once, even if the user never visits those routes.

? View Code Example
// All route components are imported upfront
import React from "react";
import { Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import Contact from "./pages/Contact";

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/about" element={<About />} />
      <Route path="/contact" element={<Contact />} />
    </Routes>
  );
}

export default App;

This approach loads all pages at once — increasing bundle size.

? With Lazy Loading

Using React.lazy() and Suspense, you can load routes only when needed.

? View Code Example
// Routes are loaded only when accessed
import React, { Suspense, lazy } from "react";
import { Routes, Route } from "react-router-dom";

const Home = lazy(() => import("./pages/Home"));
const About = lazy(() => import("./pages/About"));
const Contact = lazy(() => import("./pages/Contact"));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/contact" element={<Contact />} />
      </Routes>
    </Suspense>
  );
}

export default App;

? Explanation

Each page component is fetched only when the user navigates to that route, reducing the initial bundle size.

⚙️ Using createBrowserRouter (v6.6+)

? View Code Example
// Native lazy routing using createBrowserRouter
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import React, { Suspense, lazy } from "react";

const Home = lazy(() => import("./pages/Home"));
const Dashboard = lazy(() => import("./pages/Dashboard"));
const NotFound = lazy(() => import("./pages/NotFound"));

const router = createBrowserRouter([
  { path: "/", element: <Home /> },
  { path: "/dashboard", element: <Dashboard /> },
  { path: "*", element: <NotFound /> }
]);

export default function AppRouter() {
  return (
    <Suspense fallback={<div>Loading Page...</div>}>
      <RouterProvider router={router} />
    </Suspense>
  );
}

? Lazy Loading Nested Routes

? View Code Example
// Nested routes with individual fallbacks
<Route path="/dashboard" element={<Dashboard />}>
  <Route
    path="analytics"
    element={
      <Suspense fallback={<div>Loading Analytics...</div>}>
        <Analytics />
      </Suspense>
    }
  />
</Route>

? Interactive Simulator

Click the buttons below to see how the browser fetches "chunks" and how <Suspense> shows a fallback UI during the network delay.

 
 
 
localhost:3000/

? Home Page

Main bundle loaded.

? Use Cases

  • Large React applications
  • Admin dashboards
  • Public websites with many pages
  • Performance-critical SPAs

? Tips & Best Practices

  • Always wrap lazy-loaded routes in <Suspense>.
  • Lazy load pages, not tiny reusable components.
  • Group routes logically for better bundle splitting.
  • Provide meaningful loading UI.

? Try It Yourself

  1. Convert existing route imports to React.lazy().
  2. Add a custom spinner as fallback UI.
  3. Observe network requests per route.
  4. Lazy load nested dashboard pages.