Reputation: 113
I'm trying to make an application that shows Covid 19 numbers. I want to show global numbers when the component is rendered, so I used useEffect hooks for this. When I try to display global.confirmed
it's returns an object but when I try to display global.confirmed.value
I get a Cannot read property 'value' of undefined
error. How can I fix this?
import React from "react";
import "./App.css";
import axios from "axios";
import { useState, useEffect } from "react";
import "./App.css";
const App = () => {
const [countries, SetCountries] = useState([]);
const [cases, SetCases] = useState([]);
const [global, SetGlobal] = useState({});
const urlGlobal = "https://covid19.mathdro.id/api/"
const urlCountries = "https://covid19.mathdro.id/api/countries/";
useEffect(() => {
axios.get(urlGlobal).then(res => SetGlobal(res.data))
axios.get(urlCountries).then((res) => SetCountries(res.data.countries));
}, []);
const showCases = (e) => {
const urlCases = `https://covid19.mathdro.id/api/countries/${e.target.value}`;
axios.get(urlCases).then((res) => SetCases(res.data));
};
return (
<div>
<div>
<p>Infected</p>
<p>{cases.confirmed.value}</p>
<p>{cases.lastUpdate}</p>
<p>Number of active cases of COVID-19</p>
</div>
<div>
<p>Recovered</p>
<p>{cases.recovered.value}</p>
<p>{cases.lastUpdate}</p>
<p>Number of recoveries from COVID-19</p>
</div>
<div>
<p>Deaths</p>
<p>{cases.deaths.value}</p>
<p>{cases.lastUpdate}</p>
<p>Number of deaths caused by COVID-19</p>
</div>
<select name="countries" onChange={(e) => showCases(e)}>
{countries.map((val, i) => (
<option key={i} value={val.name}>
{val.name}
</option>
))}
</select>
</div>
);
};
export default App;
Upvotes: 3
Views: 2021
Reputation: 218818
By default you set cases
to an empty array:
const [cases, SetCases] = useState([]);
And on the initial render, while it's still an empty array, you try to access properties which aren't defined on an array:
<p>{cases.confirmed.value}</p>
There are essentially two problems here:
confirmed
. Do you expect cases
to be an object instead?cases
has no data, so don't attempt to display that data.Let cases
start off undefined
(since in the usage it looks like it shouldn't even be an array):
const [cases, SetCases] = useState();
And only display it when it's not undefined
:
<div>
<p>Infected</p>
<p>{cases && cases.confirmed.value}</p>
<p>{cases && cases.lastUpdate}</p>
<p>Number of active cases of COVID-19</p>
</div>
You can repeat for other usages, or wrap all of the usages in a single check for cases
:
{
cases &&
<div>
<p>Infected</p>
<p>{cases.confirmed.value}</p>
<p>{cases.lastUpdate}</p>
<p>Number of active cases of COVID-19</p>
</div>
}
The idea is that these elements won't even try to render if cases
is "falsey" (which undefined
is), so the code won't try to access properties like confirmed
until cases
exists.
However, if cases
should be an array, then what you also have is a logical error in your overall markup structure because arrays don't have properties like confirmed
. Perhaps you meant to calculate values from within the array. If that's the case then you can keep the initial state as an empty array:
const [cases, SetCases] = useState([]);
But you'd need to change your markup to something that uses an array. For example, maybe something like:
{
cases.map(c => (
<div>
<p>Infected</p>
<p>{c.confirmed.value}</p>
<p>{c.lastUpdate}</p>
<p>Number of active cases of COVID-19</p>
</div>
))
}
I'm not entirely familiar with the data you're using or how you want it displayed, but a key consideration here is simply the difference between an object and an array of objects. Which you'll need to determine in your code.
Upvotes: 3