Memexplanation: React Suspense, lazy loading, and fallback

In this tutorial (and meme), we look at using Suspense and fallback for lazily loaded React components

Memexplanation: Using React Suspense and Fallback for lazy loading components

The meme 👇🏽

The explanation👇🏽

So in this quick tutorial, we'll use React’s lazy imports and suspense to show a loading message while the component bundle is being loaded.

Setup

You'll need:

Step 1: Creating the React App

First, let's set up the app using the following command in your terminal:

npm create vite@latest

When asked, select JavaScript. And give it any name.

We have a simple React application structured into two main files: App.jsx and Posts.jsx. The app fetches a list of posts from a placeholder API and displays them. However, the twist lies in how the Posts component is loaded and rendered.

Step 2: Replace the contents of App.jsx

import { Suspense, useState, lazy } from "react";
import reactLogo from "./assets/react.svg";
import viteLogo from "/vite.svg";
import "./App.css";

const Posts = lazy(() => import("./Posts"));

function App() {
  const [posts, setPosts] = useState([]);

  const getPosts = async () => {
    const resp = await fetch("https://jsonplaceholder.typicode.com/posts");
    const json = await resp.json();
    return json;
  };

  const loadData = async () => {
    const postsFromServer = await getPosts();
    setPosts(postsFromServer);
  };

  return (
    <>
      <div>
        <a href="https://vitejs.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <button onClick={loadData}>Load Data</button>
      {posts.length ? (
        <Suspense fallback={<h2>🌀 Loading...</h2>}>
          <Posts posts={posts} />
        </Suspense>
      ) : null}
    </>
  );
}

export default App;

In App.jsx, React's lazy function dynamically imports the Posts component, which means Posts won't be loaded until it's needed. This is particularly useful for improving the initial load time of your application. However, because Posts is loaded lazily, we need a way to handle the loading state gracefully — that's where Suspense comes in.

The Suspense component wraps around Posts and specifies a fallback UI (<h2>🌀 Loading...</h2>) that displays while waiting for the Posts component to load. This provides immediate feedback to the user, making the loading process feel more responsive and less jarring.

Step 3: Replacing the contents of Posts.jsx

/* eslint-disable react/prop-types */

const Posts = ({
  posts
}) => {
  return (
    <div>
      <ul>
        {
          posts.map(post => <li key={post.id}>{post.title}</li>)
        }
      </ul>
    </div>
  )
}

export default Posts

Posts.jsx is straightforward; it takes a list of posts and renders them. Thanks to lazy and Suspense in App.jsx, this component's loading is optimized and doesn't impact the initial rendering performance of the application.

Explanation

By employing lazy loading with Suspense, we defer loading parts of our application until they are actually needed. This not only improves the load time but also conservatively uses resources, leading to a smoother experience for the end-user in low network conditions etc.

Conclusion

Just as you might use a fallback plan when hosting guests, using Suspense and lazy in your React applications provides a fallback UI during component loading. It's a simple yet effective way to enhance user experience, making your application feel faster and more responsive.

So, next time you're building a React app, ask yourself, "Do I have a fallback for this?" Your users might not see what's happening behind the curtain, but they'll definitely appreciate the seamless experience.

Don’t forget to subscribe for all the code snippets 🚀

Join the conversation

or to participate.