Fetching data with React hooks and Axios
Tags: react, reacthooks, javascript, axios
Published: 2021-09-09 11:28:10

I have to be honest that I was getting a bit rusty with React lately, I've been working on mostly backend and CLIs stuff for the past few months, and as I have a very bad memory I tend to forget how things, I used not so long ago, works.

As now I have to work on the front facing part of the application, I need to fetch information from the API and display them, a solution could be to run something like this:

```javascript
// mycomponent.js
import React, { useEffect, useState} from 'react';
import axios from 'axios';

const MyComponent = () => {
  const [loading, setLoading] = useState(true);
  const [data, setData] = useState([])

  useEffect(() => {
    const fetchData = async () =>{
      setLoading(true);
      try {
        const {data: response} = await axios.get('/stuff/to/fetch');
        setData(response);
      } catch (error) {
        console.error(error.message);
      }
      setLoading(false);
    }

    fetchData();
  }, []);

  return (
    <div>
    {loading && <div>Loading</div>}
    {!loading && (
      <div>
        <h2>Doing stuff with data</h2>
        {data.map(item => (<span>{item.name}</span>))}
      </div>
    )}
    </div>
  )
}

export default MyComponent;
```

So essentially we tell the component that when it mounts, it should call the `fetchData` function to populate our `data` array from the API, and we put some conditions to not show anything while we area loading our data.

The code above is fine as it is, but it stores a bit of logic in the component itself.

If you need to reuse the same logic in another component, that perhaps renders the same data but in a different way, you need to duplicate it, making the code not very DRY.

## Custom hooks FTW

I firmly believe that abstraction is always a good way to go, and in my opinion a better solution is to create a custom react hook, where essentially we move the logic of fetching the data to another file, and we make it a reusable hook that can be called from multiple components if needed.

The code for the hook will be something like this:

```javascript
// use-fetch-data.js
import { useEffect, useState} from 'react';
import axios from 'axios';

const useFetchData = () => {
  const [data, setData] = useState({});
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const { data: response } = await axios.get('/stuff/to/fetch');
        setData(response);
      } catch (error) {
        console.error(error)
      }
      setLoading(false);
    };

    fetchData();
  }, []);

  return {
    data,
    loading,
  };
};

export default useFetchData;
```

> Note: for the sake of keeping the code short I didn't manage the state for errors, relying just on `console.error`.

Now we can refactor our component code, removing all the logic and the states we no longer need, to a much shorter code:

```javascript
//mycomponent.js
import React from 'react';
import useFetchData from './hooks/use-fetch-data.js'

const MyComponent = () => {
  const {
    data,
    loading,
  } = useFetchData();

  return (
    <div>
    {loading && <div>Loading</div>}
    {!loading && (
      <div>
        <h2>Doing stuff with data</h2>
        {data.map(item => (<span>{item.name}</span>))}
      </div>
    )}
    </div>
  )
}

export default MyComponent;
```

I hope it will help you understanding better React hooks with this practical example.