Search code examples
reactjsundefinedconditional-rendering

ReactJS crashes when mapping over array being called from API and returning undefined


I am learning ReactJS and building a small app that fetches data from an API and renders it on the page. I have a sidebar that has a list of regions and makes an API call to retrieve all countries in the region on click.

    function getOccurrence(array, value) {
      return array.filter((v) => (v === value)).length;
    }

    let uniqueRegions = totalRegions.filter((v, i, a) => a.indexOf(v) === i);

    let lis = [];
    for (let i = 0; i < uniqueRegions.length -1; i++) {
      lis.push(
        <li className="nav-item" key={i} onClick={props.sideBar}>
          <span className="nav-link bg-success mb-1"><strong>{uniqueRegions[i]}</strong> - {getOccurrence(totalRegions, uniqueRegions[i])}</span>
          <ul>
          {this.props.regionData.map((country, index) => <li key={index}>{country.name}</li>) || null}
          </ul>
        </li>

      )

    }

However, the initial click calls the function and returns an undefined array. When mapping over the briefly undefined array, it crashes the app. I'd like to map over the array and return an li for each item in the array.

I've attempted conditional rendering the desired element {country.name} and returning null if the array is undefined, but when the array is defined, the desired element doesn't render. Below is the function that runs on click, and the callback function that sets state on the regional data.

  sideBarData = () => {
    let totalRegions = this.state.nations.map(a => a.region)
    function getOccurrence(array, value) {
      return array.filter((v) => (v === value)).length;
    }
    let uniqueRegions = totalRegions.filter((v, i, a) => a.indexOf(v) === i);
    for (let i = 0; i < uniqueRegions.length -1; i++) {
      this.setState({
        regionData: this.findAllByRegion(uniqueRegions[i])
      })
    }
  }

  findAllByRegion = (region) =>{
    return Axios
     .get('https://restcountries.eu/rest/v2/region/' + region)
     .then(res => {
       if(res.status === 200 && res !== null){
        this.setState(prevState =>({
          regionData: res.data
        }))
         console.log(this.state.regionData);
       } else {
         throw new Error('No country found');
       }
       })
       .catch(error => {
         console.log(error)
         return []
       });
   };

I expect the line {this.props.regionData.map((country, index) => <li key={index}>{country.name}</li>) || null} to be null when the array is undefined, but the DOM doesn't update the li when the array is defined.


Solution

  • Just check if you get valid data from the api, where you set your state do the following, in your findAllByRegion

    this.setState(prevState =>({
      // always validate your response.
      // if res is undefined doing res.data will crash your app
       regionData: res && res.data || []  
    }))