Checkout my CSS Grid By Example and Getting Started With React video courses on Skillshare. Sign up now and get one free month of Skillshare.

Show loading indicators in NextJs 13 with React Suspense

There are 2 main ways to show loading indicators in NextJs: using the loading.js file or React Suspense. This article focuses on the second approach, on how we can use the React Suspense feature to show a loading state.

First example of loading indicators with React Suspense in Next 13

We will start from the basic example discussed in how to do a simple GET request with NextJs 13. The scope of that example was to just fetch some posts and show them on a blog page:

As in the example showing an animated loading indicator, we will add an intentional delay when fetching these posts:

// app/feed.js
import Article from "./article"

const api = 'https://jsonplaceholder.typicode.com/posts?_limit=3'

const delayFetch = (url, options) =>
  new Promise((resolve) => {
    setTimeout(() => resolve(fetch(url, options))
    , options.delay)
  })

const loadDataFromServer = async (delay)=> {
    const response = await delayFetch(api, {delay})
    return response.json()
}

export default async ({delay}) => {
    const articles = await loadDataFromServer(delay)
    return (<>
        {articles.map( p => <Article key={p.id} {...p}/>)}
    </>)
}

The main page will use this feed to show the posts:

// app/page.js
import Feed from './feed'

export default () => {
    return (<>
        <Feed delay={5000} />
    </>)
}

If we want to add the loading state using React Suspense all we need to do is place the feed component in the suspense wrapper and provide the component that will be shown to the user as the data is fetched:

import Feed from './feed'
import { Suspense } from 'react'

export default () => {
    return (<>
        <Suspense fallback={<p>Loading posts ... </p>}>
          <Feed delay={5000} />
        </Suspense>
    </>)
}

Using React Suspense to show loading indicators for multiple components

One advantage of using React Suspense over the loading.js file is how easy it makes to have multiple components on the same page with different loading states.

Let's say we want to have two feeds, each having to load its data. We don't know for sure when each fetching will be done. To simulate this, we will just add different delay times for each feed:

export default () => {
    return (<>
          <Feed delay={5000} />
          <Feed delay={2000} />
    </>)
}

Given the flexibility of the React Suspense, we can just wrap each component in its own loading indicator:

import Feed from './feed'
import { Suspense } from 'react'

export default () => {
    return (<>
        <Suspense fallback={<p>Loading posts with a delay of 5s ... </p>}>
          <Feed delay={5000} />
        </Suspense>

        <Suspense fallback={<p>Loading posts with a delay of 2s ... </p>}>
          <Feed delay={2000} />
        </Suspense>
    </>)
}

With this in place, we will get 2 loading states for each feed:

And we can show the data as soon as it's available while the other feed is still loading:

You can download the full code here.

I may be wrong but at a first glance, the loading.js approach was designed for the full page/app level, while the React Suspense provides a much low-level component control. Please write me and let me know your opinions.

Home Screencasts Best of Newsletter Search X