Reputation: 169
I am building a tracker application in React using an open source API. I am using Axios for HTTP requests. When I pass the objects retrieved from the GET function in index.js, I get an error that reads:
TypeError: Cannot read property 'NewConfirmed' of undefined
Does anyone know why this may be happening based on the code below and why the parameters are coming back undefined? I tried to change my de-structuring of the parameters to reflect the way the API structures it, but it did not work.
index.js
import axios from 'axios';
const url = 'https://api.covid19api.com/summary';
export const fetchData = async () => {
try {
const { data: { Global: { NewConfirmed, TotalConfirmed, NewDeaths, TotalDeaths, NewRecovered, TotalRecovered, } } } = await axios.get(url);
return { NewConfirmed, TotalConfirmed, NewDeaths, TotalDeaths, NewRecovered, TotalRecovered, } ;
} catch (error) {
console.log(error);
}
}
App.js
import React from 'react';
import {Cards, Chart, CountryPicker} from './components';
import styles from './App.module.css';
import {fetchData} from './api';
class App extends React.Component {
state ={
data: {},
}
async componentDidMount() {
const fetchedData = await fetchData();
this.setState({data: fetchedData});
}
render() {
const { data } = this.state;
return(
<div className={styles.container}>
<Cards data = {data} />
<CountryPicker />
<Chart />
</div>
);
}
}
export default App;
Cards.jsx
import React from 'react';
import {Card, CardContent, Typography, Grid} from '@material-ui/core';
import styles from './Cards.module.css';
const Cards = ({data: { Global: { NewConfirmed, TotalConfirmed, NewDeaths, TotalDeaths, NewRecovered, TotalRecovered } } }) => {
return(
<div className = {styles.container}>
<Grid container spacing={3} justify="center">
<Grid item component={Card}>
<CardContent>
<Typography color="textSecondary" gutterBottom>New Confirmed</Typography>
<Typography variant="h5">{NewConfirmed.value}</Typography>
<Typography color="textSecondary">REAL DATE</Typography>
<Typography variant="body2">Number of active cases of COVID-19.</Typography>
</CardContent>
</Grid>
<Grid item component={Card}>
<CardContent>
<Typography color="textSecondary" gutterBottom>Total Confirmed</Typography>
<Typography variant="h5">{TotalConfirmed.value}</Typography>
<Typography color="textSecondary">REAL DATE</Typography>
<Typography variant="body2">Number of active cases of COVID-19.</Typography>
</CardContent>
</Grid>
<Grid item component={Card}>
<CardContent>
<Typography color="textSecondary" gutterBottom>New Deaths</Typography>
<Typography variant="h5">{NewDeaths.value}</Typography>
<Typography color="textSecondary">REAL DATE</Typography>
<Typography variant="body2">Number of active cases of COVID-19.</Typography>
</CardContent>
</Grid>
<Grid item component={Card}>
<CardContent>
<Typography color="textSecondary" gutterBottom>Total Deaths</Typography>
<Typography variant="h5">REAL DATA</Typography>
<Typography color="textSecondary">REAL DATE</Typography>
<Typography variant="body2">Number of recoveries of COVID-19.</Typography>
</CardContent>
</Grid>
<Grid item component={Card}>
<CardContent>
<Typography color="textSecondary" gutterBottom>New Recovered</Typography>
<Typography variant="h5">REAL DATA</Typography>
<Typography color="textSecondary">REAL DATE</Typography>
<Typography variant="body2">Number of deaths of COVID-19.</Typography>
</CardContent>
</Grid>
<Grid item component={Card}>
<CardContent>
<Typography color="textSecondary" gutterBottom>Total Recovered</Typography>
<Typography variant="h5">REAL DATA</Typography>
<Typography color="textSecondary">REAL DATE</Typography>
<Typography variant="body2">Number of deaths of COVID-19.</Typography>
</CardContent>
</Grid>
</Grid>
</div>
)
}
export default Cards;
Upvotes: 0
Views: 230
Reputation: 3274
in fetchData your reading a Global object but you're returning just the content of the Global object not Global itself. Then in Cards you're receiving props as Global again, but it's just the Global content.
You have:
const Cards = ({data: { Global: { NewConfirmed, TotalConfirmed, NewDeaths, TotalDeaths...
But it should be:
const Cards = ({data: { NewConfirmed, TotalConfirmed, NewDeaths, TotalDeaths...
Upvotes: 1
Reputation: 599
You are fetching API results after the compountDidMount (i.e. when the render method is called). So your component is rendering without any data and NewConfirmed
is undefined since your API call didn't finish yet.
Try adding a check before rendering the component.
import React from 'react';
import {Card, CardContent, Typography, Grid} from '@material-ui/core';
import styles from './Cards.module.css';
const Cards = ({data: { Global: { NewConfirmed, TotalConfirmed, NewDeaths, TotalDeaths, NewRecovered, TotalRecovered } } }) => {
if (!NewConfirmed) return null;
return(
<div className = {styles.container}>
<Grid container spacing={3} justify="center">
<Grid item component={Card}>
<CardContent>
<Typography color="textSecondary" gutterBottom>New Confirmed</Typography>
<Typography variant="h5">{NewConfirmed.value}</Typography>
<Typography color="textSecondary">REAL DATE</Typography>
<Typography variant="body2">Number of active cases of COVID-19.</Typography>
</CardContent>
</Grid>
<Grid item component={Card}>
<CardContent>
<Typography color="textSecondary" gutterBottom>Total Confirmed</Typography>
<Typography variant="h5">{TotalConfirmed.value}</Typography>
<Typography color="textSecondary">REAL DATE</Typography>
<Typography variant="body2">Number of active cases of COVID-19.</Typography>
</CardContent>
</Grid>
<Grid item component={Card}>
<CardContent>
<Typography color="textSecondary" gutterBottom>New Deaths</Typography>
<Typography variant="h5">{NewDeaths.value}</Typography>
<Typography color="textSecondary">REAL DATE</Typography>
<Typography variant="body2">Number of active cases of COVID-19.</Typography>
</CardContent>
</Grid>
<Grid item component={Card}>
<CardContent>
<Typography color="textSecondary" gutterBottom>Total Deaths</Typography>
<Typography variant="h5">REAL DATA</Typography>
<Typography color="textSecondary">REAL DATE</Typography>
<Typography variant="body2">Number of recoveries of COVID-19.</Typography>
</CardContent>
</Grid>
<Grid item component={Card}>
<CardContent>
<Typography color="textSecondary" gutterBottom>New Recovered</Typography>
<Typography variant="h5">REAL DATA</Typography>
<Typography color="textSecondary">REAL DATE</Typography>
<Typography variant="body2">Number of deaths of COVID-19.</Typography>
</CardContent>
</Grid>
<Grid item component={Card}>
<CardContent>
<Typography color="textSecondary" gutterBottom>Total Recovered</Typography>
<Typography variant="h5">REAL DATA</Typography>
<Typography color="textSecondary">REAL DATE</Typography>
<Typography variant="body2">Number of deaths of COVID-19.</Typography>
</CardContent>
</Grid>
</Grid>
</div>
)
}
export default Cards;
Upvotes: 1