Suspense in React 18

Suspense is a JSX Element/Component which we use to wrap around child components such that whilst they are loading, we can display something else, like a progress page or other fallback page.

This has obvious uses when your React application starts up and potentially loads data from a remote source etc.

Suspense understands, what the React documentation calls “Suspense-enabled data sources”. These include data fetching frameworks such as Relay and Next.js. Also the lazy import keyword lazy and also can understand promises with the (currently experimental) use hook.

Before we use components within the Suspense boundary, they need to be lazy imported.

A simple example of usage would be

<Suspsense fallback={<Loading />}>
   <Header />
   <NavBar />
   <Content />
   <StatusBar />
</Suspsense>

In this example, the Suspense boundary will load the child components, Header, NavBar etc. whilst loading we’ll see the fallback component. Upon completion that will be removed and we’ll see our full application.

But as mentioned, we need to lazy import these components so we’re have imports like this

const Header = lazy(()=> import("./components/Header"));
const NavBar = lazy(()=> import("./components/NavBar"));
const Content = lazy(()=> import("./components/Content"));
const StatusBar = lazy(()=> import("./components/StatusBar"));

There’s a requirement for lazy imported code to exported as default. If you don’t want to or cannot change the export to default (for example if using micro frontends that you didn’t write) then we can get around this with slightly more verbose syntax.

const Header = React.lazy(() => import("header/Header")
   .then(module => ({ default: module.Header })));

lazy is returning a promise, we can use the continuation as shown above (the then clause), to assign the module’s export to the default: parameter.

Along with use of Suspense to load the children whilst display a fallback, lazy also allows components to be selectively loaded, i.e. not everything is loaded at once, which has obvious results in ensuring better performance when not all components need loading initially, so using Suspense we also now have a nice way to load parts of our application as and when required as distinct parts of an application, each with a fallback. With lazy we also have more options for code splitting to reduce bundle size etc.