Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create nested JSX list items from multi-level nested array of objects reactjs

I am trying to create a nested JSX list items from nested object array. Below is the array:

[
  {
    "id": 1,
    "name": "USA",
    "values": [
      {
        "id": 2,
        "name": "Chevy",
        "values": [
          {
            "id": 3,
            "name": "Suburban"
          },
          {
            "id": 4,
            "name": "Camaro",
            "values": [...]
          }
        ]
      },
      {
       "id": 5,
       "name": "Ford",
       "values": [...]
      }
    ]
  }
]

Below is what the array should be converted to:

<ul>
  <li>USA
    <ul>
      <li>Chevy
        <ul>
          <li>Suburban</li>
          <li>Camaro</li>
        </ul>
      </li>
      <li>Ford</li>
    </ul>
  </li>
</ul>

Here is my approach:

const resultArray = [];
data.forEach((item) => {
  resultArray.push(
    <li>{item.name}
  )
  if(item.values){
   //recursively iterate and push into array
  }
  resultArray.push(</li>); //React does not allow this
});
return resultArray;

React does not allow adding individual markups into array. Please help provide a solution.
P.S.: I apologize in advance if you find something wrong with formatting. This is the first time I am posting on stackOverflow.

like image 700
Archit Avatar asked Dec 24 '22 02:12

Archit


2 Answers

You can "render" your children into a variable and use this directly in your component. The trick then is to use a recursive component. That way it doesn‘t matter how deep your tree is. You don‘t need to edit this component if your tree gets deeper.

Here is how that might look like:

function ListItem({ item }) {
  let children = null;
  if (item.values) {
    children = (
      <ul>
        {item.values.map(i => <ListItem item={i} key={i.id} />)}
      </ul>
    );
  }

  return (
    <li>
      {item.name}
      {children}
    </li>
  );
}

Here is a working example on Codesandbox with your data.

like image 184
Jan Peter Avatar answered Apr 30 '23 12:04

Jan Peter


You should push the entire node to the array at once. Have a render method like this.

const getNode = (data) => {
  return (
    <ul>
      {data.map((item) => (
        <li>
          USA
          <ul>
            {item.values && item.values.length
              ? item.values.map((subItem) => (
                  <li>
                    {subItem.name}
                    <ul>
                      {subItem.values && subItem.values.length
                        ? subItem.values.map((subSubItem) => <li>{subSubItem.name}</li>)
                        : null}
                    </ul>
                  </li>
                ))
              : null}
          </ul>
        </li>
      ))}
    </ul>
  );
};

And call that method in your render function with the data

const RenderList = (data) => {
  return (
    <div>
      { getNode(data) }
    </div>
  );
};

export default Layout;
like image 41
Dinesh Pandiyan Avatar answered Apr 30 '23 11:04

Dinesh Pandiyan