Deploying React AppsEntry 4 of 11
Fallback UI with <Suspense>
<Suspense> shows a fallback while a lazy component's code downloads.
react.dev<Suspense>
Notes
- Lazy components suspend rendering until their code arrives;
<Suspense>decides what to show meanwhile. fallbackaccepts any JSX: text, a spinner, a skeleton.- Wrap each lazy route element, or wrap the
<Outlet />in the layout once to cover all children. - Suspense covers code loading. Loader data pending state comes from
useNavigation()(see React Router, Entry 12).
What / Why / When
- What
Loading UI for lazy code.
- Why
Without it, React throws an error when a lazy component suspends.
- When
Around every lazy-loaded component.
Code compare
// App.tsx — per routeimport { Suspense } from 'react';{ index: true, element: ( <Suspense fallback={<p>Loading...</p>}> <BlogPage /> </Suspense> ), loader: () => import('./pages/Blog').then((module) => module.loader()),},{ path: ':id', element: ( <Suspense fallback={<p>Loading...</p>}> <PostPage /> </Suspense> ), loader: (args: LoaderFunctionArgs) => import('./pages/Post').then((module) => module.loader(args)),},// pages/Root.tsx — or once for all children<main> <Suspense fallback={<p>Loading...</p>}> <Outlet /> </Suspense></main>Lazy routes need no fallback: the router waits for the code like it waits for resolvers. For lazy parts of a template, @defer is the counterpart of lazy() + <Suspense>.
@defer (on viewport) {<app-comments-chart [data]="data()" />} @placeholder {<p>Chart will load when visible.</p>} @loading (minimum 300ms) {<p>Loading...</p>} @error {<p>Could not load chart.</p>}Differences and gotchas
@deferalso controls when to load (on viewport,on idle,on interaction,when condition). React'slazy()loads on first render; delay it by rendering conditionally.@errorhas no built-in Suspense equivalent; use an error boundary (or the route'serrorElement) for failed chunk loads.
Quick reference
| React | Angular |
|---|---|
<Suspense fallback={...}> | @loading / @placeholder |
lazy() component inside Suspense | @defer { <app-x /> } |
Error boundary / errorElement | @error |
| Load on first render | on idle / on viewport / on interaction |