What does React.lazy() do?
What React.lazy() does
React.lazy() lets you load a component not right at startup, but only when it's actually needed (for example, on navigating to a page, opening a modal, etc.).
Syntax:
const MyComponent = React.lazy(() => import('./MyComponent'));React.lazy()accepts a function that returns a dynamic import (import()).- This import returns a Promise that loads the JS file with the component.
- React loads the component itself once it reaches it in the render tree.
Example without React.lazy (everything loads right away)
import HeavyChart from './HeavyChart';
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<HeavyChart /> {/* loads immediately */}
</div>
);
}The HeavyChart component (for example, using chart.js or d3) loads right away,
even if it's not visible or not needed yet.
The startup load is heavy and slow.
Example with React.lazy()
import React, { Suspense, lazy } from 'react';
const HeavyChart = lazy(() => import('./HeavyChart'));
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<div>Loading chart...</div>}>
<HeavyChart />
</Suspense>
</div>
);
}Now:
HeavyChartisn't part of the main bundle.- React loads it only on the first render that reaches
<HeavyChart />. - While the component isn't loaded, a placeholder from
fallbackis shown (<div>Loading...</div>).
How this works "under the hood"
- When React encounters
<HeavyChart />:
- it triggers a dynamic import ->
import('./HeavyChart'); - Webpack / Vite creates a separate JS chunk (for example,
HeavyChart.chunk.js).
- While the chunk is loading, React shows the
fallbackfrom<Suspense>. - Once loading is finished:
- React renders the component;
- the "lazy" part of the app becomes active.
You must wrap it in <Suspense>
React.lazy() only works inside a <Suspense> component,
because Suspense is responsible for showing a "placeholder" while loading:
<Suspense fallback={<Spinner />}>
<LazyComponent />
</Suspense>Without <Suspense> React will throw an error:
A React component suspended while rendering, but no fallback UI was specified.Example of lazy-loading pages (Routing)
A very popular case:
import { lazy, Suspense } from 'react';
import { Routes, Route } from 'react-router-dom';
const Home = lazy(() => import('./pages/Home'));
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Settings = lazy(() => import('./pages/Settings'));
function App() {
return (
<Suspense fallback={<div>Loading page...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
);
}Now every page loads in a separate chunk - only when the user actually navigates to it.
What happens at build time
Webpack / Vite split the code into chunks:
main.js
Home.chunk.js
Dashboard.chunk.js
Settings.chunk.js- When the app loads, only
main.jsis loaded. - When the user navigates to
/dashboard-> React does aGET Dashboard.chunk.js. - This way, the startup load becomes much faster.
When to use React.lazy()
Great for:
- pages and routes (routing);
- modal windows and dialogs;
- heavy components (tables, charts, editors, maps);
- settings panels and tabs that are opened rarely;
- admin panels and SPAs where not everything is needed right away.
When you don't need React.lazy()
Overusing it can hurt UX:
- if the component is small and light, it's better to load it right away;
- if the component is almost always needed (for example,
Header,NavBar); - if you need SSR (server-side rendering) -
React.lazy()only works on the client (other solutions are needed, such asnext/dynamic).
Comparing "before" and "after"
| Behavior | Without React.lazy() | With React.lazy() |
|---|---|---|
| Loading | All components at once | Only when needed |
| Startup JS size | Large | Smaller |
| Startup speed | Slower | Faster |
| Fallback | None | Shown during loading |
| SSR support | Yes | Only in client rendering |
How to combine it with prefetch/preload
You can "preload" the chunk in advance on hover, to make the transition instant:
const LazySettings = lazy(() => import('./Settings'));
function Nav() {
const handleMouseEnter = () => import('./Settings'); // prefetch
return <button onMouseEnter={handleMouseEnter}>Settings</button>;
}React won't render the component right away,
but the Settings.chunk.js file will be loaded in advance.
Summary
| What it does | How it helps |
|---|---|
| Deferred loading of components | Splits code into chunks |
| Speeds up app loading | Smaller startup JS |
Works with <Suspense> | Shows a fallback while loading |
| Simple to use | const Comp = lazy(() => import('./Comp')) |
| Loads "on demand" | Only when the component is actually needed |
In simple terms:
React.lazy()is a way to tell React: "Don't load this component right away - load it when the user actually needs it."
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.