loading...

Using React Hooks and async/await to make a Covid-19 Virus Tracker

davidbell_space profile image David Bell Originally published at davidbell.space ・3 min read

Let's build a Corona virus Tracker app with React. We will be using this free API Corona Stats that @mathdroid has kindly made for us.

This will be a basic code along style article.

File cleanup

In create react app clean up the files you don't need. Then create a a DisplayContainer component and import it into App. Or do your prefered way of filing.

import React from "react"

function App() {
  return <div>Hello World</div>
}

export default App
Enter fullscreen mode Exit fullscreen mode

Display Container

import React from "react"

const DisplayContainer = () => {
  return <div>DISPLAY CONTAINER</div>
}

export default DisplayContainer
Enter fullscreen mode Exit fullscreen mode
import DisplayContainer from "./components/DisplayContainer"

function App() {
  return (
    <div>
      <DisplayContainer />
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Fetching the data

We are going to use Reacts useState and useEffect hooks.

  • useState allows you to add state to a functional component in React
  • useEffect is used for when you want something to happen when the page is rendered or a change is made.

Start by importing useState and useEffect from React. Then create the state to use. We want loading, error and stats state as these are the things we want to manage.

const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
const [stats, setStats] = useState([])
Enter fullscreen mode Exit fullscreen mode

Our function will be an async/await function. I'm going to use a try/catch/finally block for this. I find it's nice and easy to visualise like this.

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

const DisplayContainer = () => {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [stats, setStats] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      try {

      } catch (error) {

      } finally {

      }
    }
  })
Enter fullscreen mode Exit fullscreen mode

We have our state and layout laid out let's add the rest.

Fetching data and set state

try - we need to get the data from our end point using fetch. Then convert the data to JSON for us to use. Next set the state with this JSON data.

try {
  const response = await fetch("https://covid19.mathdro.id/api")
  const data = await response.json()
  setStats(data)
}
Enter fullscreen mode Exit fullscreen mode

catch - In our catch block we set the error state. If there is an error that is.

 } catch (error) {
        setError(error);
 }
Enter fullscreen mode Exit fullscreen mode

finally - The last thing we want this function to do is set the loading state to false.

finally {
        setLoading(false);
  }
Enter fullscreen mode Exit fullscreen mode

The full data fetching function looks like this.

useEffect(() => {
  const fetchData = async () => {
    try {
      const response = await fetch("https://covid19.mathdro.id/api")
      const data = await response.json()
      setStats(data)
    } catch (error) {
      setError(error)
    } finally {
      setLoading(false)
    }
  }
  setLoading(true)
  fetchData()
}, [])
Enter fullscreen mode Exit fullscreen mode

Notice at the end of useEffect there is an empty array []. This is where dependencies go to perform this function again. You must add an empty array for this else you will encounter the dreaded infinite loop.

Now check the state in your React dev tools to see if it has worked successfully. We want the confirmed, recovered and deaths stats from the api.

Displaying the data

If you checked the state in the dev tools you'll see our state is an object with objects.

Now if you try to display the stats like this stats.confirmed.value you will get an error TypeError: stats.confirmed is undefined. This is because you are trying to display something that doesn't exist yet. You must first check if it exists. This is done with a simple ternary operator.

  • ternary operator - "If this is true, do this, if not do this instead."
return (
  <div style={{ textAlign: `center` }}>
    <h2>Confirmed:</h2>
    <span>
      {stats.confirmed ? stats.confirmed.value : "Sorry not available"}
    </span>
    <h2>Deaths:</h2>
    <span>{stats.deaths ? stats.deaths.value : "Sorry not available"}</span>
    <h2>Recovered:</h2>
    <span>
      {stats.recovered ? stats.recovered.value : "Sorry not available"}
    </span>
  </div>
)
Enter fullscreen mode Exit fullscreen mode

Finish

There we have the Corona virus stats displayed.

Finished App

import React, { useState, useEffect } from "react"

const DisplayContainer = () => {
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState(null)
  const [stats, setStats] = useState({})

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch("https://covid19.mathdro.id/api")
        const data = await response.json()
        setStats(data)
      } catch (error) {
        setError(error)
      } finally {
        setLoading(false)
      }
    }
    setLoading(true)
    fetchData()
  }, [])


  return (
    <div style={{ textAlign: `center` }}>
      <h2>Confirmed:</h2>
      <span>
        {stats.confirmed ? stats.confirmed.value.toLocaleString() : null}
      </span>
      <h2>Deaths:</h2>
      <span>{stats.deaths ? stats.deaths.value.toLocaleString() : null}</span>
      <h2>Recovered:</h2>
      <span>
        {stats.recovered ? stats.recovered.value.toLocaleString() : null}
      </span>
    </div>
  )
}

export default DisplayContainer
Enter fullscreen mode Exit fullscreen mode

I have used .toLocaleString() to format the numbers. Now it just needs some CSS.

Let's connect

Twitter

Discussion

pic
Editor guide