Using React 18’s Suspense to Improve Code Quality of Web Loaders

How familiar are you with using suspense for React 18?
React 18
React 18

The React Suspense component was first launched with React 16.6, and it has been further expanded with the release of React 18. Initially, React Suspense could only be used for code splitting with the React.lazy API. However, the React team has worked to improve Suspense’s capabilities, with the goal of making it work with data fetching in the future as well.

This shows why it is critical for React developers to understand how to work with React Suspense. This article discusses how to improve the code quality of web loaders by using Suspense in React 18.

Let’s get started.

Understanding React Suspense

Let’s start with how the <Suspense> component works with the lazy loading components.

When using the Suspense component, you must provide a fallback option. It accepts any React components or even a string to render while the lazy component is loading.

Take a look at the example below, which uses the Suspense wrapper to display a typical loader until the <LazyLoadComponent> is ready.

import { lazy, Suspense } from 'react';
const LazyLoadComponent = lazy(() => import('./LazyLoadComponent'));

function MyComponent() {
  return (
    <Suspense fallback={<Loader />}>
      <div>
        <LazyLoadComponent />
      </div>
    </Suspense>
  );
}

Within a single Suspense component, you can place one or more lazy components. You can also place multiple Suspense wrappers, and the one closest to a lazy component will be used.

To learn how to utilize this, look at the code piece below.

<Suspense fallback={<MainLoader />}>
  <Suspense fallback={<SideContentLoader />}>
    <SideContent />
  </Suspense>
  <MainContent />
  <Suspense fallback={<CommentsLoader />}>
    <Comments />
  </Suspense>
</Suspense>

Suspense wrappers are used separately for the <SideContent/> and <Comments/> components in the example. As a result, if the <MainContent/> component is ready to load, it will do so regardless of whether the other two components have loaded. However, because all three components are children of the <MainContent/> component’s Suspense, the other two components will wait until the <MainContent/> component is loaded.

You can also look at the code sandbox implementation of the above example to gain a better understanding of it.

Now, let’s take a look at the enhancements Suspense received in React 18.

Improvements for Suspense in React 18

Server-Side Rendering

Suspense is no longer limited to lazy components, thanks to React 18’s new concurrent rendering. You can now use Suspense to wrap any React component in your component tree and specify their loading state declaratively.

In both of the previous examples, you can replace the lazy components with normal components and Suspense will still function according to the same principles.

This greatly simplifies the process of adding loaders to your web app.

startTransition API

Another new feature of React 18 is the startTransition API, and it can be used to improve the use of Suspense.

When switching between tab views, it would be undesirable if the previously displayed loader was shown to the user again after the user had seen the content. In such cases, useTransition() Hook and the startTransition() function can be used to display the old UI until the new UI is ready to be displayed. The startTransition API can help you avoid unexpected fallbacks by marking non-urgent UI updates as transitions.

Consider the following example code piece, in which two tab components, Cricket and Football, are wrapped in a Suspense component.

const [isPending, startTransition] = useTransition();
function handleClick() {
  startTransition(() => {
    setTab('football');
  });
}
<Suspense fallback={<Loader/>}>
  <div style={{opacity: isPending ? 0.8 : 1 }}>
    {tab === 'cricket' ? <Cricket /> : <Football />}
  </div>
</Suspense>

Here, if the useTransition() was not used, then the loader will appear each time the user switches between the tabs. However, when used as shown, the Cricket tab will be displayed until the Football tab is ready. During the transition, the user will be able to interact with the content as usual. The isPending value is used to determine whether the transition is currently occurring or not, and it is used in the example to change the opacity of the component while the transition is occurring.

Why use React Suspense

Without Suspense, we have to access the state and write a bunch more code to display loaders in React. The code piece below demonstrates how to display loaders without using Suspense.

function MyComponent() {
  const [isLoading, setIsLoading] = useState(false);
  return (
      <div>
          {isLoading ? (
              <Loader />
          ) : (
              <AppContent />
          )}
      </div>
  );
}

At first glance, the change from isLoading ? to <Suspense> may not appear to be significant, but in large projects, it will make a significant difference. When React improves Suspense to work with data fetching as well, things will get even better.

Suspense has been added to React 18 for data fetching in the frameworks Relay, Next.js, Hydrogen, and Remix. Although Suspense allows for ad hoc data fetching, the React team does not recommend it as a general practice just yet.

Conclusion

This article covered the Suspense component, new improvements to Suspense in React 18, and why you should use Suspense. I hope you now have a clear grasp of the Suspense component. So, start using Suspense and improve the quality of your React code.

Thank you for reading, and happy coding!