The problem: a giant bundle
When you bundle a React application, all the code from every component ends up in a single file (the bundle). If your app is large, the browser has to download, parse and execute all that JavaScript before painting the first screen, even if the user is only going to see the home page.
Code splitting breaks the bundle into smaller chunks that are loaded
only when they're needed. React makes this easy with two
pieces: React.lazy and <Suspense>.
React.lazy: importing a component lazily
React.lazy takes a function that returns a dynamic import(). The component's
module is not downloaded until React first tries to render it:
import { lazy } from "react";
// Panel's code lives in its own chunk and is downloaded on demand.
const Panel = lazy(() => import("./Panel"));
The import("./Panel") must point to a module with a default export that
is the component.
Suspense: what to show while it loads
Because the download is asynchronous, there's a moment when the component isn't
available yet. <Suspense> defines the fallback (a placeholder) that is
shown while the load resolves:
import { lazy, Suspense } from "react";
const Panel = lazy(() => import("./Panel"));
function App() {
return (
<Suspense fallback={<p>Loading…</p>}>
<Panel />
</Suspense>
);
}
- While
Paneldownloads, the user seesLoading…. - When it finishes, React replaces the fallback with the real component.
- A single
<Suspense>can wrap several lazy components; it will show the fallback until all of them are ready.
When to use it
Code splitting shines at natural boundaries: routes (each page in its own chunk), heavy modals, editors, charts… Any part that isn't needed on the initial load. The result is a faster startup: the user downloads less JavaScript to see the first screen.
Environment note:
React.lazyandSuspenserely on asynchronous module loading, so in these exercises we study them at a conceptual level (in the quizzes). You will practice the synchronous hooks with real code.