Skip to main content

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:

javascript
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)

javascript
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()

javascript
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:

  • HeavyChart isn'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 fallback is shown (<div>Loading...</div>).

How this works "under the hood"

  1. When React encounters <HeavyChart />:
  • it triggers a dynamic import -> import('./HeavyChart');
  • Webpack / Vite creates a separate JS chunk (for example, HeavyChart.chunk.js).
  1. While the chunk is loading, React shows the fallback from <Suspense>.
  2. 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:

javascript
<Suspense fallback={<Spinner />}> <LazyComponent /> </Suspense>

Without <Suspense> React will throw an error:

javascript
A React component suspended while rendering, but no fallback UI was specified.

Example of lazy-loading pages (Routing)

A very popular case:

javascript
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:

javascript
main.js Home.chunk.js Dashboard.chunk.js Settings.chunk.js
  • When the app loads, only main.js is loaded.
  • When the user navigates to /dashboard -> React does a GET 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 as next/dynamic).

Comparing "before" and "after"

BehaviorWithout React.lazy()With React.lazy()
LoadingAll components at onceOnly when needed
Startup JS sizeLargeSmaller
Startup speedSlowerFaster
FallbackNoneShown during loading
SSR supportYesOnly in client rendering

How to combine it with prefetch/preload

You can "preload" the chunk in advance on hover, to make the transition instant:

javascript
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 doesHow it helps
Deferred loading of componentsSplits code into chunks
Speeds up app loadingSmaller startup JS
Works with <Suspense>Shows a fallback while loading
Simple to useconst 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 ready
Premium

A concise answer to help you respond confidently on this topic during an interview.