How to fetch data from more than one API in one project. Covid Map project - day 3.
Tags: react, project, leaflet
Published: 2021-05-01 20:32:37

---
title: How to fetch data from more than one API in one project. Covid Map project - day 3.
published: true
description: 
tags: react, project, leaflet
canonical_url: http://makneta.herokuapp.com/post/covid-map-react-project-day-3/
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7jntssrcrf5zmbe2hsde.png
series: Covid Map React Project
---
Last time I was writing about fetching the data from one API using a custom useFetch hook.
Part 2 [Covid Map React project day 2](https://dev.to/makneta/covid-map-react-project-day-2-4ph2)
It was a few days ago. In the meanwhile, I decided to add a few more APIs and was trying to find out the best way of doing it. I felt a bit helpless because my app was crashing over and over again. In fact, it was not a problem with fetching the data but with displaying it. But this problem postponed my writing here. 

## Things I've done:

1. After all these trials and errors I decided to still be using useFetch hook but fetch data using Promise.all(). 
* First, in App.js I created a list of URLs 

```javascript
  const urls = [
    'https://disease.sh/v3/covid-19/countries',
    'https://disease.sh/v3/covid-19/all',
    'https://disease.sh/v3/covid-19/historical?lastdays=30',
    'https://disease.sh/v3/covid-19/vaccine/coverage/countries?lastdays=30'
  ]
```
and pass the `urls` into the useFetch() function in useFetch.js file 
```javascript
const useFetch = (urls) => 
```

* Then I created a bunch of variables and functions using useState. 

```javascript
 const [countries, setCountries] = useState(null);
    const [countrJson, setCountrJson] = useState(null);
    const [global, setGlobal] = useState(null);
    const [dataHistorical, setDataHistorical] = useState(null)
    const [dataVaccine, setDataVaccine] = useState(null)
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(null);
```

* Next, I change a bit the `try` part of my useEffect().

```javascript 
const res = await Promise.all(links.map((url) => fetch(url)))
const data = await Promise.all(res.map((r) => r.json()))
```
Promise.all() is the JavaScript method that goes over iterable (list of links in my case) and returns a single Promise for each link or if something goes wrong we have a message about an error.

* My next step was to transform data from countries API into geoJson to display data on a map. I also need the same data as a simple json, so I created one more variable for it. 
* I set all the data as React states
```javascript 
  setCountries(geoJson)
  setCountrJson(data[0])
  setGlobal(data[1])
  setDataHistorical(data[2])
  setDataVaccine(data[3])
  setLoading(false)
```
* I returned all the data 
```javascript 
 return { countries, countrJson, global, dataHistorical, dataVaccine, loading, error}
```

* To make it work I also had to access those variables in App.js component.
```javascript
const { countries, countrJson, global, dataHistorical, dataVaccine, loading, error } = useFetch(urls)
```

### useFetch.js 
```javascript
import { useState, useEffect } from 'react';

const useFetch = (urls) => {
    const [countries, setCountries] = useState(null);
    const [countrJson, setCountrJson] = useState(null);
    const [global, setGlobal] = useState(null);
    const [dataHistorical, setDataHistorical] = useState(null)
    const [dataVaccine, setDataVaccine] = useState(null)
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(null);
    

    useEffect(() => {
        const fetchData = async () => {
            const links = urls
            console.log(links)
            setLoading(true);
            try {
              const res = await Promise.all(links.map((url) => fetch(url)))
              const data = await Promise.all(res.map((r) => r.json()))
                

              const geoJson = {
                type: "FeatureCollection",
                features: data[0].map((country = {}) => {
                  const { countryInfo = {}} = country;
                  const { lat, long: lng} = countryInfo;
                    return {
                       type: "Feature",
                       properties: {
                           ...country,
                       },
                       geometry: {
                           type: "Point",
                           coordinates: [lat, lng]
                       }
                    }
                  })
                }
                
                setCountries(geoJson)
                setCountrJson(data[0])
                setGlobal(data[1])
                setDataHistorical(data[2])
                setDataVaccine(data[3])
                setLoading(false)
            } catch (error) {
                console.log(`Failed to fetch data: ${error.message}`, error)
                setError(error)
            }
       
      
        }
        fetchData()
    },[])


    return { countries, countrJson, global, dataHistorical, dataVaccine, loading, error}
}

export default useFetch
```

### And App.js
```javascript
import './App.css';
import Map from './components/Map'
import Header from './components/Header'
import TableSection from './components/TableSection'
import { StyledMain } from './components/modules/Sections'

import useFetch from './useFetch'


function App() {

  const urls = [
    'https://disease.sh/v3/covid-19/countries',
    'https://disease.sh/v3/covid-19/all',
    'https://disease.sh/v3/covid-19/historical?lastdays=30',
    'https://disease.sh/v3/covid-19/vaccine/coverage/countries?lastdays=30'
  ]

const { countries, countrJson, global, dataHistorical, dataVaccine, loading, error } = useFetch(urls)
     
if (error) return <p>Error!</p>;

  return (
    <div className="App">
    <Header />
    {loading ? <p>Loading ...</p> :  <Map countries={countries} /> }
    <StyledMain>
    {loading ? "" : <TableSection countries={countrJson} /> }
    </StyledMain>
    </div>
  );
}

export default App;
```
As you can see, I don't use all the data from each API yet, but I wanted to have it solved somehow before going further. 

2. I also refactored part of the code in Map.js to make the variables more readable. 

```javascript
 {props.countries ? props.countries.features.map(place => {
        const { coordinates } = place.geometry    
        const { flag, _id } = place.properties.countryInfo    
        const { country, cases, deaths, recovered, todayCases, todayDeaths, todayRecovered, updated } = place.properties;

        let date = new Date(updated)

        return (
        <Marker icon={redIcon} position={coordinates} key={place.properties.country}>
        <Popup  >
          <img src={flag} style={{width: "30px", height:"auto"}} />
          <h2>{country}</h2>
          <p><strong>Cases:</strong> {cases} | <strong>Cases Today:</strong> {todayCases}</p> 
          <p><strong>Deaths:</strong> {deaths} | <strong>Death Today:</strong> {todayDeaths}</p>
          <p><strong>Recovered:</strong> {recovered} | <strong>Recovered Today:</strong> {todayRecovered}</p>
          <p><strong>Last Update:</strong> {date.toLocaleDateString()}</p>
        </Popup>
        </Marker>
        )
      })
      : ""} 
```
I think I will redo this part again but for now, the popup looks like that: 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/msdfeyjynugxukjfizcm.png)

## Next step:
1. Create a table to display data for each country.