Adding —wait for it— Suspense to your React apps

by Dennis — 3 minutes

Ever get tired of writing the same loading spinner logic for every API call or lazy-loaded component in your React app? Meet React's <Suspense>!

What is <Suspense>?

Fundamentally, <Suspense> is React's way of letting you say, "Hey, I know this thing I'm trying to load might take a second so let's show something nice in the meantime." Think of it like the "loading…" animation for when you're fetching data or lazily loading components.

React introduced it as a part of its effort to handle more complex UI patterns without making you write tones of state management and conditional rendering logic. This allows you to pause rendering a component until something, like a promise, resolves. And while it's waiting, you can show a fallback UI, something like a spinner, a skeleton, or even a pretty inspirational quote about patience (okay, maybe not that, but you get the idea).

Lazy Loading Components: <Suspense> + React.lazy()

One of the most common use cases for <Suspense> is lazy loading components. This is perfect for applications in which you do not want everything loaded up front. Maybe your users don't need to see that huge dashboard until they navigate to it. Instead of having them waiting while everything loads at once, load it when they need it.

Here's a simple example:

import { type ComponentType, Suspense, lazy } from "react";
import LoadingSpinner from "@/components/LoadingSpinner";

const LazyComponent = lazy(() =>
  delayForDemo(import("@/components/LazyComponent"))
);

function App() {
  return (
    <Suspense fallback={<LoadingSpinner />}>
      <LazyComponent />
    </Suspense>
  );
}

// Add a fixed delay so you can see the loading state
function delayForDemo(promise: Promise<{ default: ComponentType<any> }>) {
  return new Promise((resolve) => {
    setTimeout(resolve, 2000);
  }).then(() => promise);
}

So what is happening here? Instead of an immediate import of the LazyComponent component, lazy() will do the importing only at the time when it's needed. <Suspense> will catch the delay and show the fallback (<LoadingSpinner />) in the meantime.

But what if it takes too long?

You can use <Suspense> together with other tools, like error boundaries to manage things that may never load, such as very slow networks or server errors. This way, you'll be displaying a nice error message instead of leaving your users hanging in suspense (pun intended).

The Suspense is Real

So there you have it, a simple rundown of <Suspense>. Stay tuned for a deep dive into React's concurrent features and data fetching in SSR applications, which changes the way you build and optimize your apps. We'll have a look at how those features allow us to load data and components more efficiently, improve performance, and result in a much smoother user experience.

References

meerdivotion

Cases

Blogs

Event