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
- Part 1: It's recommended to read Part 1 for a foundational understanding of Suspense.
- 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.
- 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:
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
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
Your app will now be live on http://localhost:3000
.
Fetching Data from a Fake REST API
Now, let’s fetch data from our fake REST API running on http://localhost:7000/data
.
-
Create a New File: Inside
web-client/src/page/FiciGame/
, create a file namedfetchFici.js
. - 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))
};
};
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
, orerror
). 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.
- 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;
- 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"><</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">></span>
<span class="o"><</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">></span><span class="p">{</span><span class="nx">ficiName</span><span class="p">}</span><span class="o"><</span><span class="sr">/p</span><span class="err">>
<span className='text-9xl'>{ficiSymbol}</span>
</div>
);
};
export default Screen;
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.
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.
Top comments (2)
Hi, I wanted to kindly point out that your header image has
react
misspelled and is currently written asreat
.I wanted to draw your attention to this in case you were wanting to update as your post is gaining visibility on Twitter.
thank you for pointing that out.