React Suspense explained: How to use it for lazy loading and data fetching

Published on April 25, 2024

What is React Suspense and how to use it

React Suspense is a feature of the React library that lets a component fall back to another component while it is loading. This allows you to present a cohesive user interface that only shows page elements once they have fully loaded their content, so that your users don’t experience missing images and media, pop-in, and other UI bugs.

This article explains React Suspense’s purpose and main features, and provides practical examples showing how to use it with both data fetching and the lazy loading of components.

What is React Suspense?

React Suspense is a built-in React component that wraps around another component to change its behavior. It suspends the rendering of the other component until an operation (such as lazy loading child components or fetching data) has completed.

How does React Suspense work?

React does the initial page render and discovers a Suspense component. It then checks if any of the child components of that Suspense component are waiting for a promise to complete on any asynchronous data or resources. 

A promise can either be pending, fulfilled, or rejected. If the promise is pending, React "suspends" the rendering of that particular component as well as its children. It does this by traversing up the tree until it finds the nearest Suspense component and rendering the fallback component specified by that component’s fallback property.

Once the promise is fulfilled, this means the suspended component's data is now available. React re-renders the suspended component and its children with the newly fetched data.

If the promise is rejected, this means the data has failed to load and you'll need to handle the error.

A simple example of using Suspense to lazy load a list of books with a fallback is shown below:

In this code snippet, the Books component is being lazy loaded, and until it (and its children) are ready, the Suspense component that wraps it will display the BooksFallback component (which can contain a loading message or animation). 

Setting a fallback on the Suspense component allows you to specify another component that can be displayed while your real component is still loading

Setting a fallback on the Suspense component allows you to specify another component that can be displayed while your real component is still loading.

React Suspense and server-side rendering

React Suspense solves a number of problems when using React with server-side rendering. You'll notice improvements in performance and user experience — as well as SEO benefits.

This is because React no longer has to wait for the server to render the entire page before it can be displayed. Instead, you can use  renderToPipeableStream to load the most important parts of the page first, and progressively load the remaining parts once the page has been delivered. In the meantime, Suspense is used to display fallbacks.

What are the main features of React Suspense and when should you use them?

Suspense is best used when you want to display a fallback while waiting for something to load. The two main use cases for this are when you’re waiting for data to be fetched from an API after the initial page load and when you're lazy loading other React components.

The <Suspense> component

This is simple to use. You just need to wrap this around any component that you want to add Suspense to, and choose a suitable fallback component for it.

It’s also possible to have multiple Suspense components, nested inside each other. This is usually used if you want to control the order in which components are displayed. For example, if details about a book were taking a long time to load, you might not want to display information about the author before the book had loaded. This code would tell Suspense to replace all the contents of the first <Suspense> tag, including the author information, with “Loading book details…” until the book data had loaded.

How to use Suspense with data fetching

Start by using the fetch() call or whatever call you use to fetch your data, and store the response in a variable.

const data = fetch()

Next, add a Suspense component around your component and specify the fallback. In this example, we are adding Suspense to a list of blog posts.

Finally, create a function that filters your data until it only contains blog posts, and map and render those blog posts as a list.

This technique of fetching your data within the code that will render your component is called “render-as-you-fetch.” It’s superior to other React data fetching patterns because it allows some data to be rendered earlier, even if not all data is available yet — providing a  better experience for the user.

The ability to use Suspense with data fetching was released in React version 18. If you want to use this feature, you’ll need a recent version of React, and a Suspense-compatible framework like Relay, Next.js, SWR, or TanStack Query. Some frameworks still aren’t 100% compatible, so make sure you read the documentation before you make any big changes.

The lazy() function

The lazy() function lets you lazy load a component. If you want to lazy load a React component, you'll need to use both the lazy() function and the Suspense component.

You first need to put the component that you want to lazy load into a separate file:

Then you need to dynamically import it by pairing lazy() with React’s dynamic import() function:

const Book = React.lazy(() => import('./Book.js'));

How to use Suspense when lazy loading React components

Suspense’s “fallback” property allows you to set a different React component as a placeholder until your desired component has finished loading.

This provides a better user experience, as your users will see an improvement in the perceived performance of your application. This refers to the fact that users will be able to see and start interacting with some parts of a page while they’re waiting for other parts to load instead of having to deal with UI inconsistencies such as empty states or flashing loading indicators.

It’s also not just perceived performance that’s improved. Suspense helps you to do code splitting, which means using lazy loading to only load data when needed. This will reduce the size of your webpack bundle, which improves initial page load times.

React Suspense code examples

Below are code examples to get you started using React Suspense for lazy loading and data fetching, as well as how to deal with error handling with Suspense.

How to use Suspense for lazy loading

Suspense can be used to display a fallback while other components load. You need to use a dynamic import for components that you want to lazy load, as well as using the lazy keyword, e.g.

const Book = lazy(() => import("./Book.js"));

A lazy-loaded component should always be nested within a Suspense component to allow React to handle what your browser should display while waiting for your component to load.

If you're defining your own component (such as <BookFallback />) for your Suspense fallback, you must make sure this doesn't use a dynamic import as it needs to be immediately available while your other component loads. The correct way to import this is:

import BookFallback from "./components";

How to use Suspense for data fetching

The Suspense component can also be used to display a fallback component while data is loading from a REST or GraphQL API, or while images and other media are loading.

This example shows how to use the Suspense component when fetching data for a product listing page. The product data for this example is stored in Contentful’s headless CMS and fetched using Contentful’s GraphQL API.

For more details about how to create data in Contentful and fetch it via the GraphQL API, you can follow along with our React tutorial.

To create this data in Contentful, create a “product” content type with the following fields: 

Name

Type

Details

inventoryProductId 

number

required, unique

description 

short text

required

imageURL 

media, one file

required

Then, in the Content tab, create three products by adding entries of the type "product". These can be a red hoodie, a green dress, and a blue T-shirt, adding an image for each.

Next, you’ll need to use React to call the Contentful GraphQL API and get the list of products, while using the Suspense component to display a fallback.  

The full code example to do this is below — paste this code into the src/App.js file of a vanilla create-react-app project, and fill in your own <CONTENTFUL_SPACE_ID> and <CONTENTFUL_API_TOKEN>, which you can set up in Settings → API keys.

To run this code, enter npm start into your terminal and then open http://localhost:3000 in your web browser.

The code shown above uses the JavaScript fetch() API to send a GraphQL query to Contentful that returns a list of products called productCollection. The ProductCollectionList React component displays all the returned items and properties as an HTML list.

While this is happening, the Suspense component that is wrapped around ProductCollectionList is displaying the fallback component and will switch to showing the ProductCollectionList once the fetch() function has completed, which is triggered when its Promise has been fulfilled.

 The asynchronous fetch() function is run, and while it’s waiting to complete, the fallback is displayed. Later, when the function has completed, the entire product list is displayed

The asynchronous fetch() function is run, and while it’s waiting to complete, the fallback is displayed. Later, when the function has completed, the entire product list is displayed.

Lazy loading blog posts, images, and content from Contentful

React Suspense means that you don’t have to write your own code to handle async operations. This lets you make your code more efficient through code splitting, and improves your users’ experience by ensuring that content displays as intended, without gaps or ugly unrendered components that are waiting for content to download.

Using a composable content platform like Contentful lets you define your content, then load it across your apps and websites, with live previews so you know exactly what your users will see, whatever device they’re using. All our API content is delivered from our high-performance CDN, so your users will never be waiting for long. This simplifies your code and improves performance — just like using React Suspense with lazy loading does.

Like React Suspense, Contentful is built on a philosophy of allowing developers to simplify their code and improve their site performance and UX. Sign up to Contentful’s free trial and start using it with React Suspense today.

Subscribe for updates

Build better digital experiences with Contentful updates direct to your inbox.

Related articles

Learn the key differences between TypeScript vs. JavaScript, and which is better. Find practical tips for migrating your existing JavaScript code to TypeScript.
Guides

TypeScript vs. JavaScript: Explaining the differences

October 24, 2023

React Server Components (RSC) are the culmination of an architectural overhaul of React itself. Let's take a tour of these changes and what they mean.
Guides

React Server Components: Concepts and Patterns

August 24, 2023

Ready to deploy Content Source Maps in a Next.js project? Enhance live previews with automatic links between displayed content and corresponding fields in Contentful.
Guides

Effortless automatic content linking in Next.js using Content Source Maps

September 30, 2024

Contentful Logo 2.5 Dark

Ready to start building?

Put everything you learned into action. Create and publish your content with Contentful — no credit card required.

Get started