React React.lazy
Table of Contents + −
In the last lesson, React Code Splitting, you learned why splitting your bundle speeds up the first load. Now you’ll use React.lazy to load a component only when it’s first shown, so it ships in its own bundle.
🤔 What does React.lazy do?
Here’s the idea in one line. React.lazy lets you load a component lazily, meaning only when it’s actually rendered, not upfront.
- Normally you
importa component at the top, so it’s part of the main bundle. React.lazychanges that to a dynamic import, loaded only when the component first appears.- Your build tool puts that component in its own separate bundle.
- So the code for it isn’t downloaded until the user reaches the part that uses it.
So React.lazy is the tool that actually performs the code split for a component.
🧩 Normal import vs lazy import
Let’s compare. Here’s a normal import, then the lazy version.
// normal import - part of the main bundle, loaded upfrontimport Dashboard from "./Dashboard";
// lazy import - its own bundle, loaded only when first renderedimport { lazy } from "react";const Dashboard = lazy(() => import("./Dashboard"));Read the lazy version carefully.
lazy(...)takes a function that returns a dynamicimport().import("./Dashboard")is the dynamic import; it loads the file on demand and returns a promise.lazywraps that, giving you a component you can use like any other.- The build tool sees the dynamic import and splits
Dashboardinto its own bundle automatically.
So the only change is swapping the static import for lazy(() => import(...)). After that, Dashboard is used exactly like a normal component.
It must be a default export
React.lazy expects the file to have a default export, which is the component. import("./Dashboard") resolves to that default. If your component is a named export, you’ll need a small extra step, but a default export is the simple, standard case.
⚠️ Lazy components need a Suspense wrapper
There’s one rule you can’t skip. A lazy component takes a moment to load, so you must wrap it in Suspense with a fallback to show during the wait.
import { lazy, Suspense } from "react";
const Dashboard = lazy(() => import("./Dashboard"));
function App() { return ( <Suspense fallback={<p>Loading...</p>}> <Dashboard /> </Suspense> );}Walk through why this is required.
- When
Dashboardis first shown, its bundle has to download, which takes a moment. - During that moment, React shows the
Suspensefallback, here “Loading…”. - Once the bundle arrives, React swaps the fallback for the real
Dashboard. - Without a
Suspensewrapper, React throws an error, because it has nothing to show while loading.
No Suspense, no lazy
A React.lazy component must be inside a Suspense boundary. If you forget it, React errors out. You’ll learn Suspense in detail next, but for now: every lazy component needs a Suspense with a fallback above it.
💡 The most common use: lazy routes
The biggest payoff is lazy-loading route pages, so each page’s code loads only when the user visits it.
import { lazy, Suspense } from "react";import { Routes, Route } from "react-router-dom";
// each page is its own lazy bundleconst Home = lazy(() => import("./Home"));const Dashboard = lazy(() => import("./Dashboard"));
function App() { return ( <Suspense fallback={<p>Loading page...</p>}> <Routes> <Route path="/" element={<Home />} /> <Route path="/dashboard" element={<Dashboard />} /> </Routes> </Suspense> );}See what this achieves.
HomeandDashboardare each lazy, so each has its own bundle.- Visiting
/loads only theHomebundle, not the dashboard’s code. - Going to
/dashboardthen loads that bundle, showing the fallback briefly. - The first load is smaller, because the user only downloads the page they opened.
So lazy routes are the classic, high-value use of React.lazy. The user downloads each page’s code just in time.
⚠️ Common Mistakes
The top mistake is using a lazy component with no Suspense around it.
// ❌ lazy component with no Suspense - React throws an errorconst Dashboard = lazy(() => import("./Dashboard"));return <Dashboard />;
// ✅ wrap it in Suspense with a fallbackreturn ( <Suspense fallback={<p>Loading...</p>}> <Dashboard /> </Suspense>);Keep these in mind.
- Don’t forget the
Suspensewrapper. Every lazy component needs one above it. - Don’t lazy-load tiny, always-shown components. The benefit is for big or route-level pieces.
- Don’t forget the file needs a default export for the simple
lazy(() => import(...))form.
✅ Best Practices
A few habits for React.lazy.
- Use it for route pages and heavy components, not small always-visible ones.
- Always wrap lazy components in a
Suspensewith a sensible fallback. - Make the fallback match the area, like a page-sized loader for a lazy route.
- Keep lazy components as default exports for the simplest syntax.
One Suspense can cover many
You don’t need a separate Suspense for every lazy component. One Suspense boundary can wrap several lazy components, showing one fallback while any of them load. Place boundaries where a shared loading state makes sense.
🧩 What You’ve Learned
- ✅
React.lazyloads a component only when it’s first rendered, not upfront - ✅ Use
const X = lazy(() => import("./X"))instead of a normal import - ✅ The build tool splits that component into its own bundle automatically
- ✅ A lazy component must be wrapped in a
Suspensewith afallback, or React errors - ✅ The most common, valuable use is lazy-loading route pages
- ✅
React.lazyexpects a default export for the simple syntax
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What does React.lazy do?
Why: React.lazy turns a component into one that loads on demand. The build tool puts it in a separate bundle that downloads only when the component is first shown.
- 2
How do you write a lazy import?
Why: You use lazy with a function that returns a dynamic import: const X = lazy(() => import('./X')). Then you use X like a normal component.
- 3
What must wrap a React.lazy component?
Why: A lazy component takes a moment to load, so it must be inside a Suspense with a fallback to show during the wait. Without it, React throws an error.
- 4
What is the most common, high-value use of React.lazy?
Why: Lazy routes are the classic use. Each page becomes its own bundle, so the user only downloads the code for the page they actually open.
🚀 What’s Next?
Now you can load components on demand with React.lazy. Next you’ll learn Suspense properly: how the fallback works and how to place boundaries well.