Home > Software engineering >  React state not displaying appropriately
React state not displaying appropriately

Time:09-21

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

  1. Provide valid initial state

    const [covid, setCovidData] = useState({ All: {} });   
    
  2. Use Optional Chaining operator to handle null checks

    <div>
      <h1>{covid.All?.country}</h1>
      <h1>{covid.All?.population}</h1>
    </div>
    
  3. Use conventional null checks/guard clauses

    <div>
      <h1>{covid.All && covid.All.country}</h1>
      <h1>{covid.All && covid.All.population}</h1>
    </div>
    
  4. Use conditional rendering

    <div>
      {covid.All && (
        <h1>{covid.All.country}</h1>
        <h1>{covid.All.population}</h1>
      )}
    </div>
    
  • Related