Mapping an array within a mapped array?

I have an array of objects in my state called ‘ideas’. Each object in the array has a property called ‘premises’, and that property is an array. I’m trying to map through ideas, and within the function map through the premises of each idea, but it doesn’t seem to be working - idea.premises is supposedly undefined. What am I doing wrong? Should I be doing this a different way anyway?

{this.state.ideas.map(idea => {
  <div className="card">
    <div className="card-body">
      <h1>{idea.title}</h1>
      {idea.premises.map(premise => {
        <p>{premise}</p>
      })}
      <p>{idea.conclusion}</p>
    </div>
  </div>
})}

.map is an array function. You can’t use it on objects, so if you have an object nested inside an array you can use .map on the outer array but not the inner object.

If you want to map through an object you can use Object.keys.map.

Something like this should work:

{this.state.ideas.map(idea => (
    <div className="card">
            <div className="card-body">
              <h1>{idea.title}</h1>
              {Object.keys.map.premises(premise => (
                <p>{premise}</p>
              ))}
              <p>{idea.conclusion}</p>
            </div>
          </div>
)}

I’m sure I have a syntax error in their somewhere but you get the idea.

Hi Nick,

I think I was a little unclear in my post, or maybe I’ve not quite understood your solution. Premises is not an object, it is an array, which is why I found this error so bizarre. This is the basic structure of state.ideas:

[
  {"title": "First idea", "premises": ["Premise one", "Premise two"], "conclusion": "Example conclusion"},
  {"title": "Second idea", "premises": ["Premise one", "Premise two"], "conclusion": "Example conclusion"},
  {"title": "Third idea", "premises": ["Premise one", "Premise two"], "conclusion": "Example conclusion"}
]

So this is an array. Each element of the array is an object. Each of those objects has a property which is an array. The first map function is called on the whole array. That works. The second map function, which gives me an error, isn’t on the objects within the array, but on the array within those objects. Surely this should work?

Thanks very much in advance for any further help!

I think you’re still running into an issue with .map.

You have an array that is inside an object which is inside another array. You can’t .map your way through this because one layer is an object.

1 Like

Ah, I get you now. Any idea why that’s the case? I supposed that there would be no problem with mapping an array within an object, because the original array which I’m able to map is itself in the state object.

Hello @joshuaboulton

Think I understood what you are trying to do.

You mean you have an array like the following and you are trying to access the elements in the arrays that are within the objects?

/* This code is not 100% identical to your code, 
but the idea is the same. I think. */

var ideas = [
  {"title": "First idea", "premises": ["Premise one", "Premise two"], "conclusion": "Example conclusion"},
  {"title": "Second idea", "premises": ["Premise one", "Premise two"], "conclusion": "Example conclusion"},
  {"title": "Third idea", "premises": ["Premise one", "Premise two"], "conclusion": "Example conclusion"}
]

To map over it, you can do the following:

/* This code is not identical to your code, 
but I think that the idea is the same. 
You just need to adjust it to your own situation. */

/* First of all, ideas array should be 
mapped like in the following */
ideas.map(val => {
/* 

Now each object will be in val, to access premises arrays, 
dot notation will help in doing that: val.premises = three arrays 

The arrays should be mapped in order to get each element 
contained therein */

	val.premises.map(x => {

/* x will be equivalent to each element in the array */

console.log(x); /*output: 
Premise one
Premise two
Premise one
Premise two
Premise one
Premise two 
*/
	});
});
1 Like

Another issue you’re having is that .map requires a return statement I believe.

1 Like

Yes, that is exactly what I’m trying to do. :slight_smile:

That’s how I thought I ought to do it, too, but it does not seem to work.

{this.state.ideas.map(idea => {
  <div className="card">
    <div className="card-body">
      <h1>{idea.title}</h1>
      {idea.premises.map(premise => {
        <p>{premise}</p>
      })}
      <p>{idea.conclusion}</p>
    </div>
  </div>
})}

This is my code. It is the same as yours, except instead of val I have idea, instead of x I have premise, and instead of a console log I have a paragraph. It’s quite puzzling to me that this won’t work. Here’s the error:

Here’s an example of mapping over a regular array:

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      myArray: [1,2,3,10]
  }
}

  render() {
    return (
      <div className="App">
        {this.state.myArray.map(x => {
          return (
            <p>{x}</p>
          );
        })}
      </div>
    );
  }
}
1 Like

Perhaps it’s meant to have a return statement - thanks, I’ll fix that! I don’t believe it’s required, though, because when I remove the second map function, the first actually works fine, without a return statement, so I doubt this is the core issue either. :confused:

It seems like this error is legitimately a little puzzling? Thanks very much for helping out guys.

In React, the return in render() is strictly required.
Be sure to add it.

1 Like

Yes, my render method has a return. It was the map functions that didn’t have returns. I’ve just added them, but the result is the same.

Based on the structure you show, would this work? My code below assumes your code was nested in a div which is rendered. It may not be and you can unjust the code accordingly.

  render() {
    return (
      <div>
        {
          this.state.ideas.map(({title, premises, conclusion}, i) => (
            <div key={i} className="card">
              <div className="card-body">
                <h1>{title}</h1>
                {premises.map((premise, j) => <p key={j}>{premise}</p>)}
                <p>{conclusion}</p>
              </div>
            </div>
          ))
        }
      </div>
    );
  }
};
3 Likes

This works! Why, may I ask?

I liked how you eliminated the need for dot notation by passing those arguments (an obj) to the callback function.

Thank you so much.

I learned something new.

1 Like

I think you solved the problem by implementing keys in the map function. What made you think that needed to be done (which it clearly did - thanks by the way)?

Funnily enough, I actually originally used ( and ), and later replaced them with { and }, believing this might’ve been what I’d done wrong!

It all makes sense now. Maybe I should have learned React from FreeCodeCamp’s curriculum - I had used other resources, and taking a look at it now, I wish I’d done this earlier. Thanks very much for the help!

That is not a feature of React but ES6 bro.
They are called Arrow functions.

1 Like