React Hooks: Loading Indicator and error handling
Tags: react
Published: 2021-04-23 01:20:37

---
title: React Hooks: Loading Indicator and error handling
published: true
date: 2021-02-22 00:00:00 UTC
tags: react
canonical_url: https://www.mariokandut.com/how-to-handle-errors-and-data-loading-state-with-react-hooks/
---

Short reminder what [React Hooks](https://www.mariokandut.com/how-to-use-react-hooks/) are, and here [useState](https://www.mariokandut.com/how-to-use-react-usestate-hook/) and [useEffect](https://www.mariokandut.com/how-to-use-useeffect-hook-in-react/) hooks in detail.

This blog article is about how to handle errors and loading indicators with useEffect. The article is a continuation of the example used in [how to fetch data with React hooks](https://www.mariokandut.com/how-to-fetch-data-with-react-hooks/).

[💰: Start your cloud journey with $100 in free credits with DigitalOcean!](https://m.do.co/c/29f238135b61)

Reminder: We want to fetch articles from [hackernews.com](https://www.hackernews.com) with a specific topic and display the resulting articles in a list with links to the corresponding article. HackerNews has a search API, which is powered by Algolia and it can be queried. As a query string you can use whatever you want, I will use `react`. The HackerNews API is public, free, and well documented, [Search Hacker News](https://hn.algolia.com/api).

The code so far:

```
import React, { useState, useEffect } from 'react';

function App() {
  const [data, setData] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      const res = await fetch(
        'https://hn.algolia.com/api/v1/search?query=react',
      );
      const json = await res.json();
      setData(json.hits);
    };
    fetchData();
  }, [setData]);

  return (
    <ul>
      {data.map(item => (
        <li key={item.ObjectId}>
          <a href={item.url}>{item.title}</a>
        </li>
      ))}
    </ul>
  );
}

export default App;
```

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#how-to-add-a-loading-indicator)How to add a loading indicator

To display a loading spinner or similar we have to know the current state of data fetching.

So we just add another state hook (useState) to handle the isLoading state and,

```
const [isLoading, setIsLoading] = useState(false);
```

set the state of `isLoading` based on the data fetching.

```
// before fetching data
setIsLoading(true);
// when data is fetching
setIsLoading(true);
```

Now, let's add it to the overall code example.

```
import React, { useState, useEffect } from 'react';

function App() {
  const [data, setData] = useState([]);
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      setIsLoading(true);
      const res = await fetch(
        'https://hn.algolia.com/api/v1/search?query=react',
      );
      const json = await res.json();
      setData(json.hits);
      setIsLoading(false);
    };
    fetchData();
  }, [setData]);

  return (
    <React.Fragment>
      {isLoading ? (
        <p>Loading ...</p>
      ) : (
        <ul>
          {data.map(item => (
            <li key={item.ObjectId}>
              <a href={item.url}>{item.title}</a>
            </li>
          ))}
        </ul>
      )}
    </React.Fragment>
  );
}

export default App;
```

Code explanation: When the effect is called for data fetching (component mounts), the loading state is set to true. Once the request resolves, the loading state is set to false again.

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#how-to-handle-errors-when-fetching-data)How to handle errors when fetching data

Proper handling of errors should be considered in every project, since the server could be not responding (maintenance, hardware problems, ...) or the request is missing some parameters or... . Think of error handling as a mandatory item on your project todo list.

Error handling with useEffect is just another state, hence another useState hook. We set the error state, when an error occurs. This is usually done in a try/catch statement, when working with async/await. You can also add the error message response from the API to your error state, for this example it will be just a boolean flag.

We add the useState for `hasError` and

```
const [hasError, setHasError] = useState(false);
```

set the state in the try/catch statement.

```
const fetchData = async () => {
  setIsLoading(true);
  setHasError(false);
  try {
    const res = await fetch(
      'https://hn.algolia.com/api/v1/search?query=react',
    );
    const json = await res.json();
    setData(json.hits);
  } catch (error) {
    setHasError(true);
  }
  setIsLoading(false);
};
```

Now let's combine this to the overall code example:

```
import React, { useState, useEffect } from 'react';

function App() {
  const [data, setData] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [hasError, setHasError] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      setIsLoading(true);
      setHasError(false);
      try {
        const res = await fetch(
          'https://hn.algolia.com/api/v1/search?query=react',
        );
        const json = await res.json();
        setData(json.hits);
      } catch (error) {
        setHasError(true);
      }
      setIsLoading(false);
    };
    fetchData();
  }, [setData]);

  return (
    <React.Fragment>
      {hasError && <p>Something went wrong.</p>}
      {isLoading ? (
        <p>Loading ...</p>
      ) : (
        <ul>
          {data.map(item => (
            <li key={item.ObjectId}>
              <a href={item.url}>{item.title}</a>
            </li>
          ))}
        </ul>
      )}
    </React.Fragment>
  );
}

export default App;
```

Code explanation: The error state is reset every time the useEffect hook runs (component mounts).

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#tldr)TL;DR

- Loading indicators increase UX and are easy to implement with useState.
- Error handling should be a mandatory step in your project.
- Error handling can be done easily with a useState hook.

Thanks for reading and if you have any **questions** , use the **comment** function or **send me a message** **[@mariokandut](https://www.twitter.com/mariokandut)**.

If you want to know more about **[React](https://www.mariokandut.com/tags/react)**, have a look at these [React Tutorials](https://www.mariokandut.com/tags/react).

References (and Big thanks):

[ReactJS](https://reactjs.org/docs/hooks-overview.html), [Dave Ceddia](https://daveceddia.com/useeffect-hook-examples/#useeffect-does-not-actively-watch), [Robin Wieruch](https://www.robinwieruch.de/react-hooks-fetch-data)