React.lazy
React.lazy
React.lazy is a function that lets you render a dynamically imported component as a regular component. It is the primary tool for implementing component-level code splitting in standard React applications.
Syntax
import { lazy } from 'react';
// The argument must be a function that calls a dynamic import()
const SomeComponent = lazy(() => import('./SomeComponent'));
How it works
When a bundler (like Webpack or Vite) encounters the dynamic import('./SomeComponent'), it knows to stop bundling code into the main JavaScript file at that point. Instead, it creates a separate, smaller JavaScript file (a chunk) specifically for SomeComponent and its dependencies.
When React attempts to render <SomeComponent /> for the first time, it triggers the dynamic import. The browser reaches out to the server, downloads the specific chunk, and then React renders it.
Usage Requirements
- Default Exports: The component you are importing with
React.lazymust be exported as thedefaultexport of its file. (Named exports are not natively supported byReact.lazywithout workarounds). - Suspense Boundary: A component imported with
React.lazymust be rendered somewhere inside a<Suspense>component. The Suspense boundary provides the fallback UI (like a loading spinner) while the chunk is downloading.
Example
import { lazy, Suspense, useState } from 'react';
// 1. Define the lazy component
const MarkdownEditor = lazy(() => import('./MarkdownEditor'));
export default function App() {
const [showEditor, setShowEditor] = useState(false);
return (
<div>
<h1>Blog Post Creator</h1>
<button onClick={() => setShowEditor(true)}>
Write Post
</button>
{showEditor && (
// 2. Wrap it in Suspense
<Suspense fallback={<div className="spinner">Loading editor...</div>}>
<MarkdownEditor />
</Suspense>
)}
</div>
);
}
In the example above, the massive code for the MarkdownEditor (and any libraries it uses, like marked or prismjs) is never downloaded by the user until they click the “Write Post” button.
Named Exports Workaround
If the component you want to lazy load is a named export (e.g., export const MyComponent = ...), React.lazy will throw an error. You can work around this by intercepting the promise returned by import() and restructuring it to look like a default export.
const MyComponent = lazy(() =>
import('./Components').then(module => ({ default: module.MyComponent }))
);
Interview Questions
Q: How does React.lazy work with default exports vs named exports?
A: React.lazy currently only supports default exports natively. If you want to lazy load a named export, you must create an intermediate wrapper module that imports the named export and re-exports it as the default.