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.
  • fallback accepts 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

React
// 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)),},
React
// 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>.

Angular
@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

  • @defer also controls when to load (on viewport, on idle, on interaction, when condition). React's lazy() loads on first render; delay it by rendering conditionally.
  • @error has no built-in Suspense equivalent; use an error boundary (or the route's errorElement) for failed chunk loads.

Quick reference

ReactAngular
<Suspense fallback={...}>@loading / @placeholder
lazy() component inside Suspense@defer { <app-x /> }
Error boundary / errorElement@error
Load on first renderon idle / on viewport / on interaction