Using React Hooks and async/await to make a Covid-19 Virus Tracker
Tags: javascript, webdev, beginners, react
Published: 2020-10-21 11:33:51



Let's build a Corona virus Tracker app with React. We will be using this free API [Corona Stats](https://covid19.mathdro.id/api) that [@mathdroid](https://twitter.com/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.

```jsx
import React from "react"

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

export default App
```

## Display Container

```jsx
import React from "react"

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

export default DisplayContainer
```

```jsx
import DisplayContainer from "./components/DisplayContainer"

function App() {
  return (
    <div>
      <DisplayContainer />
    </div>
  )
}
```

## 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.

```jsx
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
const [stats, setStats] = useState([])
```

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.

```jsx
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 {

      }
    }
  })
```

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.

```jsx
try {
  const response = await fetch("https://covid19.mathdro.id/api")
  const data = await response.json()
  setStats(data)
}
```

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

```jsx
 } catch (error) {
        setError(error);
 }
```

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

```jsx
finally {
        setLoading(false);
  }
```

The full data fetching function looks like this.

```jsx
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()
}, [])
```

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."

```jsx
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>
)
```

## Finish

There we have the Corona virus stats displayed.

![Finished App](https://dev-to-uploads.s3.amazonaws.com/i/yjzyuvegq1l5zhdy3gc0.png)

```jsx
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
```

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


## Let's connect
[Twitter](https://twitter.com/davidbell_space)