React.lazy

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 2 min

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

  1. Default Exports: The component you are importing with React.lazy must be exported as the default export of its file. (Named exports are not natively supported by React.lazy without workarounds).
  2. Suspense Boundary: A component imported with React.lazy must 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.