DEV Community

Cover image for How to fetch data from more than one API in one project. Covid Map project - day 3.
Magda Rosłaniec
Magda Rosłaniec

Posted on • Originally published at makneta.herokuapp.com

How to fetch data from more than one API in one project. Covid Map project - day 3.

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
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().
  2. First, in App.js I created a list of URLs
 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' ] 
Enter fullscreen mode Exit fullscreen mode

and pass the urls into the useFetch() function in useFetch.js file

const useFetch = (urls) => 
Enter fullscreen mode Exit fullscreen mode
  • Then I created a bunch of variables and functions using useState.
 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); 
Enter fullscreen mode Exit fullscreen mode
  • Next, I change a bit the try part of my useEffect().
const res = await Promise.all(links.map((url) => fetch(url))) const data = await Promise.all(res.map((r) => r.json())) 
Enter fullscreen mode Exit fullscreen mode

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
 setCountries(geoJson) setCountrJson(data[0]) setGlobal(data[1]) setDataHistorical(data[2]) setDataVaccine(data[3]) setLoading(false) 
Enter fullscreen mode Exit fullscreen mode
  • I returned all the data
 return { countries, countrJson, global, dataHistorical, dataVaccine, loading, error} 
Enter fullscreen mode Exit fullscreen mode
  • To make it work I also had to access those variables in App.js component.
const { countries, countrJson, global, dataHistorical, dataVaccine, loading, error } = useFetch(urls) 
Enter fullscreen mode Exit fullscreen mode

useFetch.js

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 
Enter fullscreen mode Exit fullscreen mode

And App.js

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; 
Enter fullscreen mode Exit fullscreen mode

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.

  1. I also refactored part of the code in Map.js to make the variables more readable.
 {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>  ) }) : ""} 
Enter fullscreen mode Exit fullscreen mode

I think I will redo this part again but for now, the popup looks like that:
Alt Text

Next step:

  1. Create a table to display data for each country.

Top comments (0)