You’re probably used to fetching data in React using axios or fetch. The usual method of handling data fetching is to:

Make the API call.

Update state using the response if all goes as planned.

Or, in cases where errors are encountered, an error message is displayed to the user.

There will always be delays when handling requests over the network. That’s just part of the deal when it comes to making a request and waiting for a response. That’s why we often make use of a loading spinner to show the user that the expected response is loading.

See the Pen

ojRMaN by Geoff Graham (@geoffgraham)

on CodePen.

All these can be done using a library called React Async.

React Async is a promised-based library that makes it possible for you to fetch data in your React application. Let’s look at various examples using components, hooks and helpers to see how we can implement loading states when making requests.

For this tutorial, we will be making use of Create React App. You can create a project by running:

npx create-react-app react-async-demo

When that is done, run the command to install React Async in your project, using yarn or npm:

## yarn yarn add react-async ## npm npm install react-async --save

Example 1: Loaders in components

The library allows us to make use of <Async> directly in our JSX . As such, the component example will look like this;

// Let's import React, our styles and React Async import React from 'react'; import './App.css'; import Async from 'react-async'; // We'll request user data from this API const loadUsers = () => fetch("https://jsonplaceholder.typicode.com/users") .then(res => (res.ok ? res : Promise.reject(res))) .then(res => res.json()) // Our component function App() { return ( <div className="container"> <Async promiseFn={loadUsers}> {({ data, err, isLoading }) => { if (isLoading) return "Loading..." if (err) return `Something went wrong: ${err.message}` if (data) return ( <div> <div> <h2>React Async - Random Users</h2> </div> {data.map(user=> ( <div key={user.username} className="row"> <div className="col-md-12"> <p>{user.name}</p> <p>{user.email}</p> </div> </div> ))} </div> ) }} </Async> </div> ); } export default App;

First, we created a function called loadUsers . This will make the API call using the fetch API. And, when it does, it returns a promise which gets resolved. After that, the needed props are made available to the component.

The props are:

isLoading : This handles cases where the response has not be received from the server yet.

: This handles cases where the response has not be received from the server yet. err : For cases when an error is encountered. You can also rename this to error .

: For cases when an error is encountered. You can also rename this to . data : This is the expected data obtained from the server.

As you can see from the example, we return something to be displayed to the user dependent on the prop.

Example 2: Loaders in hooks

If you are a fan of hooks (as you should), there is a hook option available when working with React Async. Here’s how that looks:

// Let's import React, our styles and React Async import React from 'react'; import './App.css'; import { useAsync } from 'react-async'; // Then we'll fetch user data from this API const loadUsers = async () => await fetch("https://jsonplaceholder.typicode.com/users") .then(res => (res.ok ? res : Promise.reject(res))) .then(res => res.json()) // Our component function App() { const { data, error, isLoading } = useAsync({ promiseFn: loadUsers }) if (isLoading) return "Loading..." if (error) return `Something went wrong: ${error.message}` if (data) // The rendered component return ( <div className="container"> <div> <h2>React Async - Random Users</h2> </div> {data.map(user=> ( <div key={user.username} className="row"> <div className="col-md-12"> <p>{user.name}</p> <p>{user.email}</p> </div> </div> ))} </div> ); } export default App;

This looks similar to the component example, but in this scenario, we’re making use of useAsync and not the Async component. The response returns a promise which gets resolved, and we also have access to similar props like we did in the last example, with which we can then return to the rendered UI.

Example 3: Loaders in helpers

Helper components come in handy in making our code clear and readable. These helpers can be used when working with an useAsync hook or with an Async component, both of which we just looked at. Here is an example of using the helpers with the Async component.

// Let's import React, our styles and React Async import React from 'react'; import './App.css'; import Async from 'react-async'; // This is the API we'll use to request user data const loadUsers = () => fetch("https://jsonplaceholder.typicode.com/users") .then(res => (res.ok ? res : Promise.reject(res))) .then(res => res.json()) // Our App component function App() { return ( <div className="container"> <Async promiseFn={loadUsers}> <Async.Loading>Loading...</Async.Loading> <Async.Fulfilled> {data => { return ( <div> <div> <h2>React Async - Random Users</h2> </div> {data.map(user=> ( <div key={user.username} className="row"> <div className="col-md-12"> <p>{user.name}</p> <p>{user.email}</p> </div> </div> ))} </div> ) }} </Async.Fulfilled> <Async.Rejected> {error => `Something went wrong: ${error.message}`} </Async.Rejected> </Async> </div> ); } export default App;

This looks similar to when we were making use of props. With that done, you could break the different section of the app into tiny components.

Conclusion

If you have been growing weary of going the route I mentioned in the opening section of this tutorial, you can start making of React Async in that project you are working on. The source code used in this tutorial can be found in their different branches on GitHub.