Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React mapping multiple arrays

Sorry for any confusion. To put simply I want to make several titles with unordered lists.

<h3>level_3 key title</h3>
<ul>
  <li>level_4 value</li>
  <li>level_4 value</li>
</ul>

<h3> another level_3 key title</h3>
<ul>
  <li>level_4 value</li>
  <li>level_4 value</li>
</ul> 

Difficult to phrase the problem into a question. Essentially having a really hard time trying to parse through some JSON and display the data correctly. What I would like to do is display level_3.x below as a top level list item and the nested level_4.x as nested list items. To be clear using React

Example:

  • KEY from level_3.1
    • String from level_4.1
    • String from level_4.2

Repeat for every level_3.x object

Example Data

"level_1":{
  "level_2.1":{
    "level_3.1":{
     "level_4.1":["string","string","string"],
     "level_4.2":["string","string","string"]
    }
    "level_3.2":{
     "level_4.1":["string","string","string"],
     "level_4.2":["string","string","string"]
    }
  }
  "level_2.2":{
     "level_3.1":{
       ... Same as above
    }
     "level_3.2":{
       ... Same as above
    }
  }
}

What I have done since you can only map an array, from my understanding, is try and go through level_3.x and push those to an Array. I can map over that and display the items as expected.

Parent Component

render(){
  return( <Child heading="A" data={resource.data} /> )
}

Child Component

render(){
  let groupObj;
  let groupArray;
  let subListItems;

  if('value' in this.props.data){
    var i;
    for(i = 0; i < Object.keys(groupObj).length; i++){
      groupArray.push(Object.keys(groupObj)[i] + "," + Object.values(groupObj)[i]) 
// Have removed the Object.values because I was trying to make everything flat and pull out the first item. Leaving it in because that was my original direction in the case it was actually the right way to go
    }
  }
  listItems = groupArray.map((item, index)=>(<li key={index}>{item}</li>));

  return({listItems})
}

Thus far I can produce:

  • level_3.1
  • level_3.2

console log > [level_3.1,level_3.2]

Which is great, and halfway there. Now where things break down is I can't seem to figure out how to get the level_4.x elements to render.

I tried writing another map function inside the previous:

listItems = groupArray.map((item, index) => (
   <li key={index}>
     {item}
     <ul>
       {subListItems = groupObj.item.map((subItem, index) => ( 
         <li key={index+1}>{subItem}</li>
       ))};
     </ul>
   </li>
 ));

This returns a map of undefined error, however if item is replaced with a key it'll work. groupObj.level_4.1.map() That will return a level_4.1 values:

  • level_3.1
    • level_4.1 value
    • level_4.1 value << unable to map level_4.2 and using item from the parent map function will return undefined

So either doing this completely wrong, or missing a way to pass in a dynamic value into that groupObj.[needs to be dynamic based on parent].map()

Note, do know that using index as a key value is an anti-pattern just have that in for sake of getting this to work.

Update

Feel like this is 90% there but having one last issue. Took both answers into consideration and the easiest for me to implement and understand what I'm typing at this time is the following:

render(){

  let listItems;
  let name = this.props.heading

  if('level_2' in this.props.data){

    let data = this.props.data.level_2[name];
    console.log('ok we can get to work', data); // <<< Good

    listItems = Object.keys(data).map((propKey) => (
      <ul key={propKey}>
       {propKey} // <<< Good
       {console.log('PROP KEY', propKey)} // <<< Good
         {data[propKey].map((childPropKey) =>{
           <li key={childPropKey}>
             {childPropKey} // <<<<<< PROBLEM, This returns nothing in the DOM
             {console.log(childPropKey)} // <<< Good
           </li>
         })}
     </ul>
   ));

return(<div>{listItems}</div>)
}

So I'm able to console.log(childPropKey) and return expected results. But just trying to return {childPropKey} nothing gets returned

Working ES5

listItems = Object.keys(data).map(function(propKey){
    return <ul key={propKey}>
      {propKey}
        {data[propKey].map(function(childPropKey){
          return <li key={childPropKey}>
            {childPropKey}
          </li>
        })}
    </ul>
  });

Working ES6

listItems = Object.keys(data).map((propKey) => (
  <ul key={propKey}>
    {propKey}
    {data[propKey].map((childPropKey) =>(
      <li key={childPropKey}>
        {childPropKey}                 
      </li>
     ))}
  </ul>
));
like image 526
wsfuller Avatar asked Feb 04 '23 05:02

wsfuller


1 Answers

Instead of trying to convert the object into an array, just cut that out and loop directly through the Object.keys array.

render () (
  <ul>
    {Object.keys(this.props.data).map((propKey) => {
      <li key={propKey}>
        {this.props.data[propKey]}

        <ul>            
          {Object.keys(this.props.data[propKey]).map((childPropKey) => {
            <li key={childPropKey}>
              {this.props.data[propKey][childPropKey]}
            </li>
          })}
        </ul>
      </li>
    })}
  </ul>
);

I've made some assumptions on your data structure, so hopefully you can translate it to your implementation.

like image 154
Nick Wyman Avatar answered Feb 06 '23 19:02

Nick Wyman