0

I got this nested arrays and I need to loop through it to create nested containers. lvl4 should go inside lvl3, lvl3 to lvl2 and lvl2 inside lvl1.

const elements = [ 
  { name: 'a-lvl1', innerEl: [ 
    { name: 'a1-lvl2', innerEl: [
      { name: 'a1-lvl3' , innerEl: [ 
        { name: 'a-lvl4', innerEl: [] }
      ] },
      { name: 'a2-lvl3' , innerEl: [ 
        { name: 'a-lvl4', innerEl: [] }
      ] }
    ] },
    { name: 'a2-lvl2', innerEl: [
      { name: 'a-lvl3' , innerEl: [ 
        { name: 'a-lvl4', innerEl: [] }
      ] }
    ] },
    { name: 'a3-lvl2', innerEl: [
      { name: 'a-lvl3' , innerEl: [ 
        { name: 'a-lvl4', innerEl: [] }
      ] }
    ] },
  ] },
  { name: 'b-lvl1', innerEl: [ { }] },
  { name: 'c-lvl1', innerEl: [ { }] }
]

This is the current script, which is working but I'm looking for a much simpler solution.

let renderElements = null;

if( elements !== undefined || elements.length != 0 ) {
  renderElements = elements.map( lvl1 => {   
    let lvl2Blocks = null;

    if( lvl1.innerEl !== undefined || lvl1.innerEl.length != 0) {
      lvl2Blocks = lvl1.innerEl.map( lvl2 => {
        let lvl3Blocks = null;

        if( lvl2.innerEl !== undefined || lvl2.innerEl.length != 0) {
          lvl3Blocks = lvl2.innerEl.map( lvl3 => {
            let lvl4Blocks = null;

            lvl4Blocks = lvl3.innerEl.map( lvl4 => {
              return (
                <div name={lvl4.name} selected={null} > 
                  { lvl4.innerEl !== undefined && lvl4Blocks }
                </div>
              )
            });

            return (
              <div name={lvl3.name} selected={null} > 
                { lvl3.innerEl !== undefined && lvl4Blocks }
              </div>
            )
          });
        }

        return (
          <div name={lvl2.name} selected={null} > 
            { lvl2.innerEl !== undefined && lvl3Blocks }
          </div>
        )
      });
    }

    return (
      <div name={lvl1.name} selected={null} > 
        { lvl1.innerEl !== undefined && lvl2Blocks }
      </div>
    )
  });
}

Any ideas? Thanks.

1 Answer 1

2

As already shown here I created a working solution for you in a Codesandbox

Again, the trick is to use recursion here. So with this simple component you will be able to render as deep as you wish.

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

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

But keep in mind that you need to fix your datastructure. If your array is supposed to be empty, don't put an empty object in it like that:

{ name: 'b-lvl1', innerEl: [ { }] },

This should look like this, or you need to modify the ListItem component to check if the first item is an empty object

{ name: 'b-lvl1', innerEl: [] },
Sign up to request clarification or add additional context in comments.

4 Comments

Awesome. Thanks! I upvoted your solution in the previous thread. Those arrays are not empty by the way. Just didn't have the time to fill them in. :)
@randomtu Thanks. Ah okey. Then ignore my statement about it ;)
Do you know of any way to improve performance when doing recurssions? stackoverflow.com/questions/53843662/…
To improve performance you need to return false in shouldComponentUpdate if you don‘t want to update it. A PureComponent does implement a shouldComponentUpdate function by itself, in which it does a shadow comparison between the properties and the state of the component.

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.