How to add a Loader to your React Project
Tags: webdev, beginners, react, css
Published: 2023-07-02 01:05:35

When working on a React project that involves requesting information from a server or handling form submissions, it is essential to keep users informed about ongoing actions. By incorporating a loader into your project, you can effectively notify users when they need to wait for these actions to complete. This article will guide you through the process of adding a loader to your React project.

## Prerequisites:

To fully understand the content of this article, it is recommended that you have a basic understanding of the following concepts:
- useState
- JSX
- Ternary operators
- CSS

## Step 1: Creating a Loading State

To introduce a loading state to your React component, you need to create a variable that represents whether the component is currently loading or not.
```
import React, { useState } from "react"
const [loading, setLoading] = useState(false)
```

## Step 2: Setting the Loading State on Action

To activate the loading state when an action occurs, such as submitting a form or clicking a button, you need to set the loading variable to true. Once the action is completed and the results are ready, you can disable the loading state by setting it back to false.

```
const [loading, setLoading] = useState(false)
const [joke, setJoke] = useState(null)

function getJoke() {
  setLoading(true)
  fetch("https://official-joke-api.appspot.com/random_joke")
    .then((response) => response.json())
    .then((data) => {
      setJoke(data)
      setLoading(false)
    })
    .catch((error) => {
      console.error(error)
      setLoading(false)
    })
}

return (
  <>
    <button onClick={getJoke}>
      Get Joke
    </button>
    {loading ? (
      <p>Loading...</p>
    ) : joke ? (
      <div>
        <h4>{joke.setup}</h4>
        <p>{joke.punchline}</p>
      </div>
    ) : null}
  </>
) 
```

The provided code snippet demonstrates how to render a button that retrieves a joke from an API upon clicking. Inside the getJoke function, we set the loading state to true when the button is clicked, initiate the fetch request, and then set the loading state back to false once the joke has been stored in the component's state.

Using this logic, we can render a div with the text "Loading..." when the loading state is true.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hs8wg7ae5l2pirososnc.gif)
_Getting a joke without a loader_
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0sar9vxwvgr7mgm1kxvh.gif)
_Getting a joke with a loader_

In the first visual, the user doesn't know if the button did anything when clicked. In contrast, in the second visual, the user is informed that their click is triggering an action.

## Adding a Spinner

Because you are rendering a JSX component you can change the div with the text "Loading..." to a spinner component, to create a spinner component follow the instructions below.

Add this to your CSS

```
.spinner {
  margin: 0 auto;
  width: 30px;
  height: 30px;
  border: 5px solid #f3f3f3;
  border-top: 5px solid #213547;
  border-radius: 50%;
  animation: spin 1s infinite linear;
  margin-top: 15px;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}
```

Create a component called Spinner

```
import React from 'react';
import "./index.css"

function Spinner() {
  return <div className="spinner"></div>;
};

export default Spinner;
```

Replace the div with the <Spinner /> component

```
return (
    <>
      <button onClick={getJoke}>Get Joke</button>
      {loading ? (
        <Spinner />
      ) : joke ? (
        <div>
          <h4>{joke.setup}</h4>
          <p>{joke.punchline}</p>
        </div>
      ) : null}
    </>
  )
```

**BONUS TIP:** Tailwind users use this component instead

```
import React from 'react';

function Spinner() {
  return (
    <div className="flex justify-center items-center">
      <div className="animate-spin rounded-full h-10 w-10 border-t-2 border-b-2 border-gray-900"></div>
    </div>
  );
};

export default Spinner;
```