Learn how to use React Suspense for data fetching (part 2)

Derick Zihalirwa - Aug 13 '22 - - Dev Community

Here's a refined version of your article to make it more understandable and engaging:


React Suspense for Data Fetching: Part 2

Hello đź‘‹,

In the first part of this series, we explored the React Suspense API, its functionality, and how it works with lazy-loaded components. If you missed that, click here to read Part 1.

In this second part, we’ll dive into how React Suspense can be used when fetching data. When an app is waiting for data to load, the user needs to see something on the screen to indicate the process. React Suspense handles this well by providing a fallback option, which displays a placeholder while the data is being fetched in the background.

Prerequisites

  1. Part 1: It's recommended to read Part 1 for a foundational understanding of Suspense.
  2. JSON Server: You should have a basic understanding of how a JSON server works. If not, I’ve written an article with examples that you can check out here.
  3. Code: The code for this article is available on GitHub. You can find it here.

Step-by-Step Guide

1. Clone the Repository

Start by cloning the repo to your local machine, and open it in your favorite text editor (I’ll be using VS Code).

The repository contains two main folders: web-client and server. In VS Code, open the terminal (Ctrl + J for Windows or Cmd + J for Mac) and navigate to the following structure:

Folder Structure

2. Install Dependencies

You’ll need two terminal windows for this. In the first terminal, navigate to the web-client folder and run:



npm install


Enter fullscreen mode Exit fullscreen mode

Do the same in the server folder using the second terminal.

3. Start the Servers

Once all dependencies are installed, start the servers:

  • In the server folder, run: ```bash

npm run serve-json

  This will start a JSON server on `http://localhost:7000`.

- In the `web-client` folder, run: 
  ```bash


  npm run dev


Enter fullscreen mode Exit fullscreen mode

Your app will now be live on http://localhost:3000.

Running the servers

Fetching Data from a Fake REST API

Now, let’s fetch data from our fake REST API running on http://localhost:7000/data.

  1. Create a New File: Inside web-client/src/page/FiciGame/, create a file named fetchFici.js.
  2. Add the Code: Paste the following code:


const fetchFici = (search) => {
    return fetch(`http://localhost:7000/data?q=${search}`)
        .then(res => res.json())
        .catch(err => console.log(err));
};

const wrapPromise = (promise) => {
    let status = 'pending';
    let result;
    let suspender = promise.then(
        res => {
            status = 'success';
            result = res;
        },
        err => {
            status = 'error';
            result = err;
        }
    );
    return {
        read() {
            if (status === 'pending') throw suspender;
            if (status === 'error') throw result;
            return result;
        }
    };
};

export const createResource = (search) => {
    return {
        data: wrapPromise(fetchFici(search))
    };
};


Enter fullscreen mode Exit fullscreen mode

How This Works

  • fetchFici(search): This function fetches data based on the provided search parameter.
  • wrapPromise(promise): It wraps the promise and tracks its status (pending, success, or error). React Suspense requires us to throw the promise while it's pending, and this function helps us manage that.
  • createResource(search): This exports the result, making it ready for Suspense to consume.

Implementing the Suspense Component

Now that we have the data-fetching logic, let’s implement it in our component.

  1. Update FiciGame Component:


import React, { Suspense, useState } from 'react';
import Spinner from '../../layout/Spinner';
import { createResource } from './fetchFici';
import Screen from './Screen';

const FiciGame = () => {
    const [fici, setFici] = useState('Fire');
    const resource = createResource(fici);

    return (
        <div className='border rounded-md bg-zinc-800 border-white p-4'>
            <p className='text-center text-3xl font-mono'>Fici Game</p>
            <Suspense fallback={<Spinner />}>
                <Screen resource={resource} />
            </Suspense>
            <ul className='flex justify-center gap-2 items-center'>
                <li onClick={() => setFici('Fire')} className='p-4 border text-2xl shadow-lg bg-gray-900 border-white'>Fire</li>
                <li onClick={() => setFici('Rock')} className='p-4 border text-2xl shadow-lg bg-gray-900 border-white'>Rock</li>
                <li onClick={() => setFici('Water')} className='p-4 border text-2xl shadow-lg bg-gray-900 border-white'>Water</li>
                <li onClick={() => setFici('Air')} className='p-4 border text-2xl shadow-lg bg-gray-900 border-white'>Air</li>
            </ul>
        </div>
    );
};

export default FiciGame;


Enter fullscreen mode Exit fullscreen mode
  1. Create the Screen Component:

Inside the same folder, create Screen.jsx:



import React from 'react';

const Screen = ({ resource }) => {
const ficiData = resource.data.read();
const { name: ficiName, symbol: ficiSymbol } = ficiData[0];

<span class="k">return </span><span class="p">(</span>
    <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">'</span><span class="s1">border bg-gray-900 flex flex-col justify-center items-center h-80 m-4</span><span class="dl">'</span><span class="o">&gt;</span>
        <span class="o">&lt;</span><span class="nx">p</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">p-4 font-mono text-lg</span><span class="dl">"</span><span class="o">&gt;</span><span class="p">{</span><span class="nx">ficiName</span><span class="p">}</span><span class="o">&lt;</span><span class="sr">/p</span><span class="err">&gt;
Enter fullscreen mode Exit fullscreen mode

<span className='text-9xl'>{ficiSymbol}</span>
</div>
);
};

export default Screen;

Enter fullscreen mode Exit fullscreen mode




Explanation:

  • resource.data.read(): This function either throws a promise (while data is loading) or returns the fetched data.
  • Once the data is available, the component displays the element's name and symbol.

Testing

To see this in action, open your browser’s DevTools, go to the Network tab, and select “Fast 3G” under throttling options. Then refresh the page to see how the fallback spinner appears while data is being fetched.

Testing

Conclusion

Congratulations! 🎉 You’ve now mastered the basics of using React Suspense for data fetching and lazy loading components. While it may seem complex initially, with more practice, it becomes second nature.

Feel free to experiment and leave your thoughts in the comments or connect with me on Twitter.

. . . . . . . . . . . .
Terabox Video Player