Loading component...

Published on August 14, 2024Reading time: 6 min read

Best Practices for Loading States in Next.js

Enhancing user experience with skeleton loading screens when fetching data from an API in Next.js

Loading component...

Related Articles

SitecoreAI

Sitecore Workflow Automation with Management API

A practical guide to managing Sitecore workflows programmatically using the Management GraphQL API with production-tested patterns.

November 20, 20251 min read
Blog Card Placeholder
Dev

How to Create a New Sitecore SXA Headless Site

SXA Headless is easy, awesome and powerful! Learn how to create your first Sitecore Headless Tenant & Site with SXA.

November 19, 20251 min read

Loading component...

Digital solutions

Learn how to maximize your investment in Sitecore by working with us.

AI solutions

Dominate your industry. Work with us to digitally transform your business.

Fishtank's proprietary project accelerator. Save time and money. Build what matters.

Utilities

Energy

Education

Healthcare

Manufacturing

Professional services

Financial services

Non-profits and associations

About FishtankThe PlaybookSitecore SnackContact us

Solutions

  • Digital solutions
  • AI solutions
  • TIDAL for XM Cloud

About

  • About Fishtank
  • The Playbook
  • Sitecore Snack
  • Contact us

Insights

Work

Industries

  • Utilities
  • Energy
  • Education
  • Healthcare
  • Manufacturing
  • Professional services
  • Financial services
  • Non-profits and associations

Start typing to search...

Create Seamless Loading Experiences in Next.js With Skeleton Screens

When building web applications with Next.js, handling loading states effectively is critical for creating a smooth user experience. When you fetch data from an API, users often experience a delay before the content is fully loaded. To enhance the user experience during this period, you can use placeholders or skeleton screens. The 'react-loading-skeleton’ npm package is a perfect tool for this purpose. This blog will guide you through the best practices for handling loading states in Next.js using this package.

Why Use Skeleton Loading Screens?

Skeleton screens provide us with a cleaner and more modern alternative to the traditional ‘spinner’ method. Skeleton screens provide a low fidelity preview of the content that will appear once data is fetched from an endpoint. This approach keeps the users engaged and sets expectations for the content layout, leading to a more seamless experience.

A Step-by-Step Guide

Install the Necessary Packages

First you must install the ‘react-loading-skeleton’ npm package. This package will provide us with ready-to-use skeleton elements that you can easily integrate into your Next.js application.

Install either:

yarn add react-loading-skeleton
npm install react-loading-skeleton

Fetching Data From Our Serverless Function

Lets imagine we have a serverless function in our Next.js application called articles, which will be called by hitting the URL/api/articles in our fetch statement. This fetch will happen after the component rendered due to the fetch statement being in the useEffect hook. Notice the empty dependency array which will only cause it to fire once. Until the fetch is complete, we would see nothing on the page.

import { useEffect } from 'react';

const HomePage = () => {
  const [articles, setArticles] = useState([]);

  useEffect(() => {
    const fetchArticles = async () => {
      try {
        const response = await fetch('/api/articles');
        const data = await response.json();
        setArticles(data);
      } catch (error) {
        console.error('Error fetching articles:', error);
      }
    };

    fetchArticles();
  }, []);

  return (
    <div className="homepage">
        articles.map(article => (
          <div key={article.id} className="article">
            <img src={article.image} alt={article.title} />
            <h2>{article.title}</h2>
            <p>{article.content}</p>
          </div>
        ))
    </div>
  );
};

export default HomePage;

Article Skeleton Component

Lets first create a low fidelity/skeleton view of the layout of an individual article. We will save this in a separate file called SkeletonArticle and import it into our component that will be fetching the article data.

// components/SkeletonArticle.tsx

import Skeleton from 'react-loading-skeleton'

const SkeletonArticle = () => {
  return (
    <div className="skeleton-article">
        <Skeleton height={64} width={64} count={1} /> // this will mock out our image
        <Skeleton height={20} width={120} count={1} /> // this will mock out our title
        <Skeleton height={16} count={3} /> // this will mock out 3 lines of body content
    </div>
  );
};

export default SkeletonArticle;

Loading useState Variable

Lets add a useState variable that will indicate that the component has not rendered yet. We will call it ‘loading’ and it will initially be set to true as the component will not have any data when the component first loads. We will also be importing our SkeletonArticle here. We will display three instances of these components to show the user what the expected layout will be and to indicate that we are currently fetching data.

import { useState, useEffect } from 'react';
import SkeletonArticle from '../components/SkeletonArticle';

const HomePage = () => {
  const [articles, setArticles] = useState<Articles>([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchArticles = async () => {
      try {
        const response = await fetch('/api/articles');
        const data = await response.json();
        setArticles(data.articles);
      } catch (error) {
        console.error('Error fetching articles:', error);
      } finally {
        setLoading(false);
      }
    };

    fetchArticles();
  }, []);

  return (
    <div>
      {loading && (
        <>
          <SkeletonArticle />
          <SkeletonArticle />
          <SkeletonArticle />
        </>
      ) : (
        articles.map((article, index) => (
          <div key={index} className="article">
            <img src={article.image} alt={article.title} />
            <h2>{article.title}</h2>
            <p>{article.content}</p>
          </div>
        ))
      )}
    </div>
  );
};

export default HomePage;

Further Considerations

Consistent Design of Screens

Ensure your skeleton screens match the design and layout of the actual content. This consistency helps users understand what to expect once the content loads.

Error Handling

Handle errors gracefully. If the API call fails, inform the user with a friendly message and provide options to retry or navigate to a different part of the application. We are just using a console log in our example but a developer could have an additional useState flag that is set to either an error returned from the API or a generic message if the API fails. Then we would display this message upon such failure.

const [apiErrorOccured, setApiErrorOccured] = useState(false);
...
// in the fetch
if (response.status !== 200) {
    setApiErrorOccured(true);
}
 ...
// in the return statement
{apiErrorOccured && (
  <div>An error has occured! Please try again later.</div>
)}

Enhance Next.js Loading States With Effective Skeleton Screens

Using skeleton screens to handle loading states in Next.js applications significantly improves user experience by providing visual feedback during data fetching. By following these best practices and integrating the ‘react-loading-skeleton’ npm package, you can create a more engaging and seamless experience for your users.



Related Links

  • Next.js and TypeScript Component Organization 101: Best Practices
  • Using Invariants in Next.js Serverless Functions to Improve Code Quality and Identify Bugs Faster
  • Why Use Serverless Functions in Next.js on Sitecore XM Cloud?

Solutions

  • Digital solutions
  • AI solutions

Brands

  • TIDAL for SitecoreAI
  • Sitecore Snack
  • The Playbook

Fishtank lore

  • Work
  • Insights
  • About us
  • Contact us

Industries

Utilities
Professional services
Energy
Financial services
Healthcare
Education
Non-profits and associations
Manufacturing
Utilities
Professional services
Energy
Financial services
Healthcare
Education
Non-profits and associations
Manufacturing

2025 @All Rights Reserved. Privacy Policy.

FISHTANK