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:
- 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
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
const useFetch = (urls) =>
- 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);
- 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()))
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)
- I returned all the data
return { countries, countrJson, global, dataHistorical, dataVaccine, loading, error}
- 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)
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
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;
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.
- 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>
)
})
: ""}
I think I will redo this part again but for now, the popup looks like that:
Next step:
- Create a table to display data for each country.
Top comments (0)