Search code examples
reactjsreact-hooksuse-effect

react useEffect fetch api data gives error TypeError: Cannot read property 'cases' of undefined


import React,{useState,useEffect} from 'react'
import {Bar} from 'react-chartjs-2';

const Chart = ({val}) => {

    
   const [Dataa,setdata] = useState([]);
   useEffect(()=>{
     async function fetchData(){
        const apiresponse =await fetch('https://disease.sh/v3/covid-19/countries');
        const apidata =await apiresponse.json();
        console.log(apidata);
        setdata(apidata);
    }
    fetchData();
},[])


 const chartData = { labels: ['Total Cases', 'Deaths', 'Recovered','Active Cases'],
  datasets: [
    {
      label: 'My First dataset',
      backgroundColor: ['#737270','red','green'],
      borderColor: 'rgba(255,99,132,1)',
      borderWidth: 1,
      hoverBackgroundColor: 'rgba(255,99,132,0.4)',
      hoverBorderColor: 'rgba(255,99,132,1)',
      data: [Dataa && Dataa[val].cases,Dataa[val].deaths,Dataa[val].recovered,Dataa[val].active]     }
  ]
}

    
      return (
        <div>
            <h2>Bar Example</h2>
            <Bar
          data={chartData}
          width={100}
          height={190}
          options={{
            maintainAspectRatio: false
          }}
        />
        </div>
    )
}
export default Chart;
<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>

Code Picture

I'm trying to fetch Covid-19 stats to show it in the bar chart but it gives an error on accessing object property. Val is the index number of the array as an array of objects is begin fetched by api.


Solution

  • When you create the chartData you are passing Dataa and you are not checking the length of it, so when you try to access the val position is undefined.

    I would suggest checking the length of Dataa before passing it.

    if (Dataa.length !== 0) {
        const chartData = { labels: ['Total Cases', 'Deaths', 'Recovered','Active Cases'],
        datasets: [
            {
                label: 'My First dataset',
                backgroundColor: ['#737270','red','green'],
                borderColor: 'rgba(255,99,132,1)',
                borderWidth: 1,
                hoverBackgroundColor: 'rgba(255,99,132,0.4)',
                hoverBorderColor: 'rgba(255,99,132,1)',
                data: [Dataa && Dataa[val].cases,Dataa[val].deaths,Dataa[val].recovered,Dataa[val].active]     
            }
       ]
       return (
        <div>
            <h2>Bar Example</h2>
            <Bar
          data={chartData}
          width={100}
          height={190}
          options={{
            maintainAspectRatio: false
          }}
        />
        </div>
       )
      }
    } else {
        // Some component while data is loading
    }
    

    You would probably want to add a spinner or something in order to show that the application is doing something to render the component. In that case, you should return that component if the Dataa.length is equal to zero