Good day, I have a project that gets a response from an API then passes down the data from parent to child. The problem is, I can easily access the response at the top level but when I try to get in the inner parts of the API (in this case, the price={statistics.quotes.USD.price}
), I'm getting the TypeError: Cannot read property 'USD' of undefined
error. I have tried console.logging the price to check if my path is correct and it is. Why could this be happening when I can access other data correctly?
Overview.js
import React, { useState, useEffect } from 'react';
import Statistics from './Statistics';
import axios from 'axios';
export default function Overview(props) {
const id = props.match.params.currency;
//some other states here
const [statistics, setStatistics] = useState({});
//some code
const fetchBasicData = async () => {
// Retrieves a coin's basic information
const apiCall = await axios.get('https://api.coinpaprika.com/v1/coins/' + id);
let basicData = await apiCall.data;
setCoin(basicData);
// Retrieves coin statistics
const fetchedData = await axios.get('https://api.coinpaprika.com/v1/tickers/' + id);
const coinStats = await fetchedData.data;
setStatistics(coinStats);
}
useEffect(function () {
if (Object.keys(coin).length === 0 && Object.keys(statistics).length === 0) {
fetchBasicData();
}
})
//some code
return (
<div>
//some other stuff
<Statistics
statistics={statistics}
lastUpdate={statistics.last_updated}
price={statistics.quotes.USD.price} // <----- this is where the error occurs
/>
</div>
);
}
Statistics.js
import React from 'react';
export default function Statistics(props) {
return (
<div>
<h1>Statistics</h1>
<p>Last updated: {props.lastUpdate}</p>
<p>Price: {props.price}</p>
<p>Market Rank: {props.marketRank}</p>
<h2>Supply</h2>
<p>Circulating supply: {props.circulatingSupply}</p>
<p>Max supply: {props.maxSupply}</p>
</div>
);
}
Hi it could be that some of rows in your data do not have quotes try doing following change it should be fixed by this
change
price={statistics.quotes.USD.price}
to
price={statistics?.quotes?.USD?.price}
? checks if given variable is present and if not return null and does not throw an error
As you are using the axios
call, which is asynchronous and the data of that call is not available on initial render, but it will be available later on. So to handle this you have to conditional render (render only when certain condition met)
Try this:
price={statistics?.quotes?.USD?.price}
Or you can also use Object.hasOwnProperty('key')
with ternary
and do the conditional render.
Error: TypeError: Cannot read property 'USD' of undefined
is saying that statistics.quotes
is undefined.
There are 2 possible causes:
statistics
isn't updated to something you're expecting.My guess is that your data fetching and state update is fine and it's just the initial render issue.
The initial statistics
state is an empty object ( {}
), so accessing any property is fine. It's when you then go a nested level deeper into the structure that causes the issue.
<Statistics
statistics={statistics} // OK: statistics => {}
lastUpdate={statistics.last_updated} // OK: statistics.last_updated => undefined
price={statistics.quotes.USD.price} // Error: can't access USD of undefined statistics.quotes
/>
const statistics = {}; console.log(statistics); // {} console.log(statistics.quotes); // undefined console.log(statistics.qoutes.USD); // error!!
You can use Optional Chaining operator ( ?.
) or guard clauses (null checks) to protect the "access X of undefined" errors.
<Statistics
statistics={statistics}
lastUpdate={statistics.last_updated}
price={statistics.quotes?.USD?.price}
/>
<Statistics
statistics={statistics}
lastUpdate={statistics.last_updated}
price={statistics.quotes && statistics.quotes.USD && statistics.quotes.USD.price}
/>
If there's even a remote chance that your statistics
state can be updated to undefined
then apply the same fix as above but just a level shallower, ie statistics?.quotes?.USD?.price
.
Alternatively you can apply some Conditional Rendering of the Statistics
component where the condition is the nested properties existing on the statistics
state.
return (
<div>
//some other stuff
{statistics.last_updated && statistics.quotes && (
<Statistics
statistics={statistics}
lastUpdate={statistics.last_updated}
price={statistics.quotes.USD?.price}
/>
)}
</div>
);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.