How to

How to Create Loading UIs in Next.js 13 Using React Suspense

Loading UIs and visual elements are important components in web and mobile applications; they play a pivotal role in enhancing user experience and engagement. Without such cues, users might become puzzled and uncertain about whether the application is functioning properly, if they triggered the right actions, or if their actions are being processed.


By providing users with various visual cues that indicate ongoing processing, you can effectively mitigate any form of uncertainty and frustration—ultimately deterring them from prematurely exiting the application.


Impact of Loading UIs on Performance and User Experience

Jakob Nielsen’s ten heuristics for user interface design emphasizes the importance of ensuring the current system status is visible to end users. This principle highlights the need for user interface components such as loading UIs and other feedback UI elements to promptly provide users with appropriate feedback, about ongoing processes, and within the required time frame.

Loading UIs play a pivotal role in shaping the overall performance and user experience of applications. From a performance perspective, implementing effective loading screens can significantly enhance a web application’s speed and responsiveness.

Man designing grayscale UX/UI design on computer.

Ideally, effectively utilizing loading UIs allows for asynchronous content loading—this prevents the entire page from freezing while specific components load in the background; essentially, creating a smoother browsing experience.

Furthermore, by offering a clear visual indication of ongoing processes, users are more likely to patiently await content retrieval.

Getting Started With React Suspense in Next.js 13

Suspense is a React component that manages asynchronous operations running in the background, such as data fetching. Simply put, this component lets you render a fallback component until the intended child component mounts and loads the required data.

Here is an example of how Suspense works. Let’s assume you have a component that fetches data from an API.

 export default function Todos() {
  const data = fetchData() {
    
    return data;
  };
  return <h1> {data.title} </h1>
}


export default function Loading() {
  return <p>Loading data ...</p> }

Suspense will display the Loading component until the content of the Todos component finishes loading and is ready for rendering. Here’s the Suspense syntax for achieving this:

 import { Suspense } from 'react';

function App() {
  return (
    <>
      <Suspense fallback={<Loading />}>
        <Todos />
      </Suspense>
    </>
  );}

Next.js 13 Supports React Suspense

Next.js 13 added support for Suspense through its app directory feature. Essentially, working with the app directory allows you to include and organize page files for a particular route within a dedicated folder.

Within this route directory, you can include a loading.js file, which Next.js will then utilize as the fallback component to display the loading UI before rendering the child component with its data.

Now, let’s integrate React Suspense in Next.js 13 by building a demo To-Do application.

You can find this project’s code in its GitHub repository.

Create a Next.js 13 Project

You will build a simple application that fetches a list of to-dos from the DummyJSON API endpoint. To get started, run the command below to install Next.js 13.

 npx create-next-app@latest next-project --experimental-app 

Define a Todos Route

Inside the src/app directory, create a new folder, and name it Todos. Inside this folder, add a new page.js file, and include the code below.

 async function Todos() {

  async function fetchTodos() {
    let res = await fetch("https://dummyjson.com/todos");
    const todosData = await res.json();
    return todosData
  }

  const {todos} = await fetchTodos();

  async function wait(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  await wait(3000);

  return (
    <>
      <div className="todo-container">
        <div className="todo-list">
          {todos.slice(0, 10).map((todo) => (
            <ul key={todo.id}>
              <div className="todos">
                <li> <h2>{todo.todo}</h2> </li>
              </div>
            </ul>
          ))}
        </div>
      </div>
    </>
  );

}

export default Todos;

The asynchronous function, Todos, fetches a list of todos from the DummyJSON API. It then maps through the array of fetched todos to render a list of todos on the browser page.

Additionally, the code includes an asynchronous wait function that simulates a delay, creating a scenario that will allow a user to see a loading UI for a specific duration before displaying the fetched todos.

In a more realistic use case; instead of simulating a delay, situations such as processing activities within applications, fetching data from databases, consuming the APIs, or even, slow API response times would cause some brief delays.

Integrate React Suspense in the Next.js Application

Open the app/layout.js file and update the boilerplate Next.js code with the following code.

 import React, { Suspense } from 'react';
import Loading from '@/app/Todos/loading';

export const metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body >
      <Suspense fallback={<Loading />}>
            {children}
      </Suspense>
      </body>
    </html>
  )
}

The app/layout.js file in Next.js 13 serves as a central layout component that defines the overall structure and behavior of the application’s layout. In this case, passing the children prop to the Suspense component, ensures the layout becomes a wrapper for the entire application’s content.

The Suspense component will display the Loading component as the fallback while the child components are loading their content asynchronously; indicating to the user that content is being fetched or processed in the background.

Update the Home Route File

Open the app/page.js file, delete the boilerplate Next.js code, and add the code below.

 import React from 'react';
import Link from "next/link";

function Home () {
  return (
    <main>
      <div>
        <h1>Next.js 13 React Suspense Loading Example</h1>
        <Link href="/Todos">Get Todos</Link>
      </div>
    </main>
  )
}

export default Home;

Create the loading.js File

Finally, go ahead, and create a loading.js file inside the app/Todos directory. Inside this file, add the code below.

 export default function Loading() {
  return <p>Loading data ...</p> }

Adding Modern Spinners to the Loading UI Component

The loading UI component you created is very basic; you can optionally choose to add skeleton screens. Alternatively, you can create and style custom loading components using Tailwind CSS in your Next.js application. Then, add user-friendly loading animations like spinners provided by packages such as React Spinners.

To use this package, go ahead and install it in your project.

 npm install react-loader-spinner --save 

Next, update your loading.js file as follows:

 "use client"
import { RotatingLines} from 'react-loader-spinner'

function Loading() {
  return (
    <div>
      <p>Loading the Todos ...</p>
      <RotatingLines
        strokeColor="grey"
        strokeWidth="5"
        animationDuration="0.75"
        width="96"
        visible={true}
      />
    </div>
  );
}

export default Loading;

Now, the loading UI will display a loading message and render a rotating lines spinner animation to indicate ongoing processing while fetching Todos data.

Improve User Experience With Loading UIs

Incorporating loading UIs into your web applications can significantly enhance user experience. By providing users with visual cues during asynchronous operations, you can effectively minimize their worries and any uncertainties, and consequently maximize their engagement.

Leave a Reply

Your email address will not be published. Required fields are marked *