Code Splitting (lazy)
Overview
When a user visits a traditional React SPA, the build tool (Vite/Webpack) bundles the entire application—every page, every massive chart library, every modal—into one giant JavaScript file (often called main.js). The browser must download, parse, and execute this massive file before it can show the user anything, resulting in terrible load times for large apps.
Code Splitting solves this by breaking the giant bundle into smaller chunks.
Using React's `lazy()` function combined with `<Suspense>`, you can tell React to only download the code for a component when it is actually needed. If a user never clicks the 'Settings' page, they will never download the 5MB of code required to run the Settings page, drastically speeding up the initial load time of the application.
Syntax
import { Suspense, lazy } from 'react';
import { Routes, Route } from 'react-router-dom';
// 1. Standard import (Included in the main bundle - Loads instantly)
import HomePage from './pages/HomePage';
// 2. Lazy import (Creates a separate chunk file. ONLY downloaded if visited!)
const AdminDashboard = lazy(() => import('./pages/AdminDashboard'));
const DataVisualizer = lazy(() => import('./pages/DataVisualizer'));
function App() {
return (
// 3. Suspense wrapper: Provides a fallback UI (like a spinner)
// while the browser pauses to download the component chunk over the network
<Suspense fallback={<div className="loading-spinner">Loading page...</div>}>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/admin" element={<AdminDashboard />} />
<Route path="/charts" element={<DataVisualizer />} />
</Routes>
</Suspense>
);
}Common Pitfalls
- Forgetting the Suspense Boundary: If you render a
lazy()component but forget to wrap it in a<Suspense>component (either immediately around it, or higher up in the tree), React will literally crash the application with an error. It needs to know what UI to display during the network request.
Interview Questions
Code splitting is the practice of breaking a monolithic JavaScript bundle into smaller, asynchronous chunks. It is critical for performance (specifically Time to Interactive) because it ensures the user only downloads the exact code they need for the current screen, rather than downloading the entire application upfront.
Route-based splitting (lazy loading pages like /admin) is the most common and highest impact, as entire sections of the app are deferred. Component-based splitting defers heavy components on the same page (like a massive 3D model or a rich-text editor hidden inside a modal) until the user actually interacts with them.
Real-World Example
Lazy Loading a Heavy Third-Party Library: By strategically lazy-loading heavy components hidden behind user interactions (modals, accordions, tabs), you can slash your initial load time in half, significantly improving Core Web Vitals and SEO.
import { Suspense, lazy, useState } from 'react';
// Imagine this component imports 'chart.js' or 'three.js' (Massive libraries)
// We don't want to force mobile users to download 2MB of chart code
// unless they explicitly click "View Charts"
const HeavyAnalyticsChart = lazy(() => import('./components/HeavyAnalyticsChart'));
function Dashboard() {
const [showChart, setShowChart] = useState(false);
return (
<main>
<h1>Dashboard Summary</h1>
<p>Revenue: $50,000</p>
<button onClick={() => setShowChart(true)}>
View Advanced Analytics
</button>
{/* The network request to download the chunk ONLY fires when showChart becomes true */}
{showChart && (
<Suspense fallback={<p>Downloading chart engine...</p>}>
<HeavyAnalyticsChart />
</Suspense>
)}
</main>
);
}Check Your Knowledge
Test your understanding of Code Splitting (lazy) with these quick questions.