My issue: My state sometimes displays, if I refresh the browser, update code I get the following error TypeError: Cannot read properties of undefined (reading 'country')
I am not sure why this behaviour occurs. In one instance it displays and another time it doesn't. Any explanation and solution would be appreciated.
My response returns a 200 status code and all the appropriate data that I console.log is legit so I am confused why this issue occurs.
App.js
import api from './api/fetchCovidData'
import { useState, useEffect } from 'react'
const App = () => {
const [covid, setCovidData] = useState({})
useEffect(() => {
const fetchCovidData = async () => {
try{
const response = await api.get('/cases?country=France');
console.log(response.data)
setCovidData(response.data);
} catch (err) {
if (err.response){
// Not in the 200 response range
console.log(err.response.data);
console.log(err.response.status);
console.log(err.response.headers);
} else {
console.log(`Error: ${err.message}`);
}
}
}
fetchCovidData();
}, []);
return (
<div>
<h1>{covid.All.country}</h1>
<h1>{covid.All.population}</h1>
</div>
);
}
export default App;
fetchCovidData.js
import axios from "axios";
export default axios.create({
baseURL: 'https://covid-api.mmediagroup.fr/v1'
});
Example Response
{
"All": {
"confirmed": 2604595,
"recovered": 195365,
"deaths": 62548,
"country": "France",
"population": 64979548,
"sq_km_area": 551500,
"life_expectancy": "78.8",
"elevation_in_meters": 375,
"continent": "Europe",
"abbreviation": "FR",
"location": "Western Europe",
"iso": 250,
"capital_city": "Paris",
"lat": "46.2276",
"long": "2.2137",
"updated": "2020/12/26 12:21:56 00"
}
}
CodePudding user response:
Problem is your initial state is empty. So, you have to check the state is empty/undefined/null or not before going to use.
return (
covid && covid.All && (<div>
<h1>{covid.All.country}</h1>
<h1>{covid.All.population}</h1>
</div>)
)
or
<div>
<h1>{covid?.All?.country}</h1>
<h1>{covid?.All?.population}</h1>
</div>
CodePudding user response:
Try to add question mark to validate if exist {covid?.All?.country} another option is to make a conditional
return (
covid && (<div>
<h1>{covid?.All?.country}</h1>
<h1>{covid?.All?.population}</h1>
</div>)
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import api from './api/fetchCovidData'
import { useState, useEffect } from 'react'
const App = () => {
const [covid, setCovidData] = useState({})
useEffect(() => {
const fetchCovidData = async () => {
try{
const response = await api.get('/cases?country=France');
console.log(response.data)
setCovidData(response.data);
} catch (err) {
if (err.response){
// Not in the 200 response range
console.log(err.response.data);
console.log(err.response.status);
console.log(err.response.headers);
} else {
console.log(`Error: ${err.message}`);
}
}
}
fetchCovidData();
}, []);
return (
<div>
<h1>{covid?.All?.country}</h1>
<h1>{covid?.All?.population}</h1>
</div>
);
}
export default App;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
CodePudding user response:
Issue
The issue here is that your initial state is an empty object:
const [covid, setCovidData] = useState({});
But you are attempting to reference a level too deep on the initial render before your state is really populated:
<div>
<h1>{covid.All.country}</h1>
<h1>{covid.All.population}</h1>
</div>
Here covid
is the empty object ({}
), and accessing into covid.All
is ok since it returns undefined
, but when you then attempt to access into covid.All.country
, well now you are attempting to access a property of an undefined object and the error is thrown (i.e. TypeError: Cannot read properties of undefined (reading 'country')
).
Solutions
Provide valid initial state
const [covid, setCovidData] = useState({ All: {} });
Use Optional Chaining operator to handle null checks
<div> <h1>{covid.All?.country}</h1> <h1>{covid.All?.population}</h1> </div>
Use conventional null checks/guard clauses
<div> <h1>{covid.All && covid.All.country}</h1> <h1>{covid.All && covid.All.population}</h1> </div>
Use conditional rendering
<div> {covid.All && ( <h1>{covid.All.country}</h1> <h1>{covid.All.population}</h1> )} </div>