tezvyn:

How do React.lazy and dynamic import() enable code splitting?

AI-drafted, machine-checkedSource: react.devintermediate
How do React.lazy and dynamic import() enable code splitting?

It tests your grasp of React code-splitting and the Suspense contract. A strong answer states that lazy defers loading until first render via dynamic import, and Suspense shows a fallback while the Promise resolves.

WHAT THIS TESTS: This question probes whether you understand React's declarative code-splitting API at a mechanical level rather than just surface syntax. The interviewer wants to see if you can articulate the exact contract between a lazy loader function, the Promise returned by dynamic import, the module shape, and a Suspense boundary. Senior candidates should demonstrate awareness of caching semantics, the default export requirement, and the distinction between network suspense and local UI state management.

A GOOD ANSWER COVERS: A strong response hits four mechanical points in order. First, lazy is a factory that accepts a loader function which must return a Promise or thenable from a dynamic import call. Second, React invokes that loader only when the component is first rendered, then caches both the Promise and its resolved value so the load never repeats across re-renders or remounts. Third, the resolved module must expose its React component as the default export, and that component type must be valid such as a function, memo, or forwardRef. Fourth, Suspense acts as a boundary that catches the thrown Promise during rendering and displays a fallback element until the Promise resolves, at which point React commits the resolved component in place of the fallback.

COMMON WRONG ANSWERS: Red flags include saying Suspense is exclusively for data fetching or server components, claiming that lazy preloads the chunk before mount, or suggesting you can consume named exports directly without re-exporting them as default. Another mistake is describing the fallback as a prop on lazy rather than on the parent Suspense boundary, or implying that the loader runs during module initialization instead of deferred first render. Confusing the Promise rejection path with a render error is also a signal that the candidate has not handled production lazy loading.

LIKELY FOLLOW-UPS: An interviewer might ask how you would handle a rejected Promise, which should be caught by an Error Boundary rather than Suspense. They may also ask how to prefetch a lazy route on hover, how server-side rendering streams interact with lazy and Suspense, or whether you can nest multiple Suspense boundaries for granular fallbacks inside a single view. You might also be asked to compare React.lazy with framework-level splitting such as Next.js dynamic.

ONE CONCRETE EXAMPLE: Imagine a settings page with a heavy Chart component. You write const Chart = lazy(() => import('./Chart.js')); and render Chart inside a Suspense boundary with fallback Spinner. When the user clicks the Analytics tab, React calls the loader, triggers the network request for the split chunk, and shows Spinner. Once the chunk arrives and the modules default export resolves to a valid component, React swaps Spinner for Chart. If the network request fails, the thrown rejection propagates to the nearest Error Boundary, which can render an error state.

Source: react.dev

Read the original → react.dev

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.