1
render() {
    return (
        <p>{this.state.recipes[0].title}</p> // This is what I believe should work - Ref Pic #1
        // <p>{this.state.recipes[0]}</p>    // This was trying random stuff to see what happens - Ref Pic #2
        // <p>{this.state.recipes.title}</p> // This was me trying crazy nonsense - Ref Pic #3
    )
}

I am attempting to traverse through some JSON and am getting some very wonky responses. If anyone would like to look at the JSON themselves, it's available at this link.

When the first p tag is run, I get the following response: This is my first question, so I can't embed images, I'm sorry.

Being unsure why it said recipes[0] was undefined, I ran it again with the second p tag soley uncommented, to which I get the following response: Still the same question, still can't embed, sorry again.

That response really caught me off guard because the keys it reference's (nid, title, etc..) are the ones I know are in the object. 'Title' is what I want.

Last, I tried just the third p tag, to which the app actually compiled with no errors, but the p tag was empty. Here's what I have in React Devtools, but I still can't embed.

Looking at < Recipes > it clearly shows that state has exactly what I want it to, and image two shows recipes[0] has the key I try to call the first time. I have searched and Googled and even treated my own loved ones as mere rubberducks, but to no avail.

What am I doing wrong?

Avery Vann
  • 11
  • 2

3 Answers3

0

you can do something like this to handle state when there is data and when there is no data

constructor(props) {
      super(props);

      this.state = {
        recipes: []
      };
    }


 render() {
             return (
                 <p>
                  {this.state.recipes && this.state.recipes.length ? {this.state.recipes[0].title} : {this.state.recipes}}       
                </p> 
             )
         }
Jibin Mathews
  • 1,129
  • 1
  • 10
  • 23
0

The error in the first p tag tells you what exactly is happening. Accessing a property of an 'undefined' will break javascript/ react.

You must probably not have the expected data in the state, to verify what I am saying, simply debug by console.log(this.state) in your render:

render() {
  console.log(this.state); // probably has this.state.recipes empty array at first render
  ...

this probably happened because your state is being populated by an async call from an api. Render will be called first before your async request from an api resolves (which means unfortunately you don't have the ..recipes[0] data yet in your state)

I am guessing you have this in your componentDidMount:

componentDidMount() {
  ThirdParty.fetchRecipes().then(data => {
     this.setState({ recipes: data.recipes }); // after setState react calls render again. This time your p tag should work.
  })
  ...

If you have newer react version I would recommend to use optional chaining because the property you are interested in is deeply nested: How to handle calling functions on data that may be undefined?

<p>{this.state?.recipes?.[0]?.title}</p>

Another effective way but too wordy:

const title =
  this.state &&
  this.state.recipes &&
  this.state.recipes.length &&
  this.state.recipes[0].title
    ? this.state.recipes[0].title
    : "";

render() {return (<p>{title}</p>)}
Tyro Hunter
  • 755
  • 1
  • 8
  • 20
  • My componentDidMount is pretty much identical to your example. It includes my fetch, then ends with the following: `.then((data) => { console.log(data) this.setState({ recipes: data }) })` The data that gets console logged is correct, and the state change should trigger a rerender, but it still says undefined. – Avery Vann Mar 24 '19 at 13:13
  • Okay now, move on to the next step: log the state this time in render, see my suggestion above. And let me know of the actual data, there's no way it's still undefined after the next re-render – Tyro Hunter Mar 24 '19 at 22:29
0

I believe you are fetching the JSON asynchronously. In that case you should consider boundary cases where your initial recipes state is an empty array.

  1. When you run the first p tag, since JSON is fetched asynchronously, initially this.state.recipes is not defined, hence you get the error.

  2. When you run the second p tag, during the first render, this.state.recipes is undefined, hence it works inside p tag, but after the JSON is fetched and state is set, render is called again and this time this.state.recipes[0] is an object, hence it can't be counted as a valid react component, thus the error shows up.

  3. With the 3rd p tag, as you have mentioned yourself, this.state.recipes.title will compile successfully with no errors, but the value will be undefined.

You just need to check for the edge cases where initial state is empty.

        constructor(props) { 
            super(props);
            this.state = { recipes: [] }
        }

        render() {
             return (
                 <p>
                  {this.state.recipes.length > 0 ? {this.state.recipes[0].title} : ''}       
                </p> 
             )
         }
Aaditya Thakkar
  • 1,750
  • 13
  • 13