Coelacanth
Coelacanth

Reputation: 867

Can't render an array inside of the ReactJS state

I'm fetching the data from an external API for food recipes, and getting the response in this format (JSON):

{
    "count": 30,
    "recipes": [
        {
            "publisher": "BBC Food",
            "f2f_url": "http://food2fork.com/view/8c0314",
            "title": "Chicken and cashew nut stir-fry",
            "source_url": "http://www.bbc.co.uk/food/recipes/chickenandcashewnuts_89299",
            "recipe_id": "8c0314",
            "image_url": "http://static.food2fork.com/chickenandcashewnuts_89299_16x9986b.jpg",
            "social_rank": 95.91061636245128,
            "publisher_url": "http://www.bbc.co.uk/food"
        },
        {
            "publisher": "Jamie Oliver",
            "f2f_url": "http://food2fork.com/view/0beb06",
            "title": "Roasted chicken breast with pancetta, leeks & thyme",
            "source_url": "http://www.jamieoliver.com/recipes/chicken-recipes/roasted-chicken-breast-with-pancetta-leeks-and-thyme",
            "recipe_id": "0beb06",
            "image_url": "http://static.food2fork.com/466_1_1349094314_lrg2129.jpg",
            "social_rank": 94.88568903341375,
            "publisher_url": "http://www.jamieoliver.com"
        },
        { ... more recipes ... }
    ]
}

And I'm trying to access that data and display, for the purpose of testing, just variables 'count', and the 'publisher' of the first recipe in array. This is my React code:

import React from 'react';

import './App.css';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { data: {} };
  }

  componentDidMount() {
    fetch('https://www.food2fork.com/api/search?key=MY_KEY&q=chicken%20breast&page=2')
    .then(response => {
      return response.json();
    })
    .then(jsonData => {
      this.setState({ data: jsonData }, function() {
        console.log(jsonData);
      });
    });
  }

  render() {
    return (
      <div className="App">
        <h1>{this.state.data.count}</h1>
        <p>{this.state.data.recipes[0].publisher}</p> // Why this doesn't work?
      </div>
    );
  }
};

If I remove the 'p' tag in the render() function, everything works as expected: the page loads at first, and then after fetching the data, displays '30' as 'h1'.
However, if I run the code with the 'p' tag, I get this error: enter image description here

I'm searching for the answers for more than two hours and really can't find the answer. Why can I access the variable 'count', but not the variable 'publisher', which is inside of an array? I'm event logging out this.state after setting it, and object looks completely normal there. How can I access the elements in the 'recipes' array?

Upvotes: 0

Views: 53

Answers (1)

Rajan Lagah
Rajan Lagah

Reputation: 2528

This is is because when you are fetching data at that time react render the component and you got error as this.state.data is still {} so this.state.data.recipes[0] is yet not defined as fetch request is not completed (it take some time). To resolve it you have to return on 2 conditions.

  1. when fetch is running (Loading)

2) when fetch is completed

 render() {
   if(!this.state.data.recipes){
    // if the fetch request is still not completed
    return (
       <div>
      <h1>Loading .... </h1>
       </div>
     )
   }
 // run when fetch request is completed and this.state.data is now assigned some data
    return (
      <div className="App">
        <h1>{this.state.data.count}</h1>
        <p>{this.state.data.recipes[0].publisher}</p> // Why this doesn't work?
      </div>
    );
  }


answer for your comment. the error is can not read property 0 of undefined which means this.state.data.recipes is undefined and thus.state.data.recipes[0] is error right?.

But when you use this.state.data.count then you did not get error. As it will print undefined that is value of count (at that moment and you are not trying to print further like this.state.data.count.toString() if you do so it will through you error can not read property toString() of undefined).
and in then() when you use this.setState() it will update the state and react will re-render all affected components.

Upvotes: 2

Related Questions