0

My React Component has the following render

componentWillMount () {
    var url = 'https://gist.githubusercontent.com/hart88/198f29ec5114a3ec3460/raw'
    Request.get(url)
    .then(data => {
        this.setState({cakes: data.text});
    })
}

render() {
    return(
        <div>
            {this.state.cakes} //prints this ok

            {
              this.state.cakes.map(cake =>{ // error here
                return <p>{cake.title}</p>;
              })
            }
        </div>
    );
}

i am trying to loop through this.state.cakes which is an array of objects.

What am i doing wrong here ?

Update - an abbreviated example of this.state.cakes:

[
    {
        "title": "Lemon cheesecake",
        "desc": "A cheesecake made of lemon",
        "image":"https://s3-eu-west-1.amazonaws.com/s3.mediafileserver.co.uk/carnation/WebFiles/RecipeImages/lemoncheesecake_lg.jpg"
    },
    {
        "title":"Banana cake",
        "desc":"Donkey kongs favourite", 
         "image":"http://ukcdn.ar-cdn.com/recipes/xlarge/ff22df7f-dbcd-4a09-81f7-9c1d8395d936.jpg"
    }
]

Thanks

7
  • What is the error that you are getting? Commented Aug 13, 2017 at 17:13
  • Can you please print what's in the Cakes array ? Because if it's array of objects (which seems most obvious here). Then the error is in ` {this.state.cakes}` line not the other one. Commented Aug 13, 2017 at 17:24
  • @MinkeshJain updated the {this.state.cakes}, Commented Aug 13, 2017 at 18:09
  • How are you loading the data into state? Is it using a fetch from a server. map is undefined because cakes isn't an array yet which means that the data is not available for use by the component. Commented Aug 13, 2017 at 18:30
  • @Spdexter - how is state.cakes defined in your component constructor? Is the example that you provided hard-coded, or as @Andy suggests, it's the result of a fetch? Commented Aug 13, 2017 at 18:49

4 Answers 4

1

If the state is set as the resutl of a fetch you might not be able to access the data immediately due to the async operation. You can catch this by inspecting the state and if it has no length return a message or a spinner component to indicate the data's on its way.

Once state.cakes is updated with the data from the fetch operation the component will re-render.

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

componentDidMount() {
  fetch('/cakes')
    .then(res => res.json())
    .then(cakes => this.setState({ cakes }));
}

render() {
  if (!this.state.cakes.length) return <Spinner />
  return (
    <div>
      {this.state.cakes.map(cake => {
        return <p>{cake.title}</p>;
      })};
    </div>
  )
}

As the others have mentioned it's also good practice to add keys to your iterated elements.

Sign up to request clarification or add additional context in comments.

8 Comments

Thanks ! i understood what u said and applied. i now get LOADING for a few secs and then get this error : Unhandled Rejection (TypeError): this.state.cakes.map is not a function :(
Add the code for your fetch operation either to your question or a jsfiddle and i'll take a look.
@Spdexter, I've added some example fetch code. Does yours look similar to that?
this is my componentWillMount () { var url = 'gist.githubusercontent.com/hart88/198f29ec5114a3ec3460/raw' Request.get(url) .then(data => { this.setState({cakes: data.text}); }) }
I was unable to get .json() working with Superagent for some reason, replaced with Fetch and it's working great- thanks for your help !
|
1

Here:

{this.state.cakes.map((cake, i) => <p key={i}>{cake.title}</p>;)}

Do not forget to add the key attribute. Ps: It would be better to use an unique Id instead of the array index. SO if you have an id for each array item, better write:

{this.state.cakes.map(cake => <p key={cake.id}>{cake.title}</p>;)}

Comments

1

I believe that you've used curly braces (understandably) where React actually requires parentheses. Since you're getting the data from a fetch, be sure to set your constructor with a preliminary cakes object as well. Try this:

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

render() {
    if (this.state.cakes.length > 0){
        return(
            <div>
                {
                    this.state.cakes.map(cake => (
                        return <p>{cake.title}</p>;
                    ))
                }
            </div>
        );
    }

    return null
}

The issue is that the component is rendering and you're telling it to do something with an array called this.state.cakes, but this.state.cakes hasn't been defined yet because the fetch hasn't returned yet. Setting your constructor like this passes an empty array to the render so it doesn't freak out, and then when your data loads and your state updates, it will re-render with your data.

The reason {this.state.cakes} was, on its own, rendering just fine is because for the first split second of the component's existence, that value was undefined, which means that React basically just ignored it - once the data loaded, it rendered. However, the map method failed because you cannot pass an undefined array into map.

And as Ha Ja suggested, you should probably add a key attribute to the <p> elements.

7 Comments

Hi thanks @skwidbreth, it didnt work-the error i get is Cannot read property 'map' of undefined!
cakes isn't an array (yet). Add the rest of the component code @Spdexter, so we can see how your state is populated with your JSON.
Er, how can you get a result from printing this.state.cakes but then have cakes as undefined in the next line of code. Are you sure cakes is an array?
How have you defined state.cakes in your constructor?
Ah yeah, you'll want to conditionally render that - see my updated answer.
|
0

You missed brackets inside of your map

    {this.state.cakes.map(cake =>{ // errors here
        return <p> {cake.title} </p>;
    })}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.