简体   繁体   中英

'TypeError: Cannot read property of x of undefined' when passing data from parent to child component but others are working

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.

Issue

Error: TypeError: Cannot read property 'USD' of undefined is saying that statistics.quotes is undefined.

There are 2 possible causes:

  1. On the initial render you are accessing too deeply into your initial state.
  2. On any subsequent render the 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!!

Solution

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM