简体   繁体   中英

React loop through nested object

I'm fetching data from strapi. The response for my navigation object looks like that (simplified):

[
   {
      "id":1,
      "title":"Home",
      "order":1,
      "items":[
         {
            "id":2,
            "title":"3D Assets",
            "order":1,
            "items":[
            ]
         },
         {
            "id":4,
            "title":"3D Plants",
            "order":2,
            "items":[
            ]
         },
         {
            "id":3,
            "title":"Surfaces",
            "order":3,
            "items":[
               {
                  "id":5,
                  "title":"Asphalt",
                  "order":1,
                  "items":[
                  ]
               }
            ]
         }
      ]
   },
   {
      "id":6,
      "title":"Collections",
      "order":2,
      "items":[
      ],
      "icon":""
   }
]

Actually I'm looping through my navigation like that:

{Object.entries(navigationItems).map(([key, value]) => {
    return(
        <div className="nav_item">
            <div className="nav_item_parent">{value.title}
            {Object.entries(value.items).map(([key, value]) => {
                    return(
                        <div className="nav_item_child">{value.title}
                            {Object.entries(value.items).map(([key, value]) => {
                                    return(
                                        <div className="nav_item_child">{value.title}</div>
                                    )
                            })}                                         
                        </div>
                    )
            })} 
            </div>
        </div>
    )
})}

在此处输入图像描述

How can I create a navigation without repeating the code for each child? (Because the object could be nested many times)

Here just placing some demo code, please have reference and implement as per your need Parent Component

    import React, {Children} from 'react';

function recursionExample(props) {
  let data = [
    {
      id: 1,
      title: 'Home',
      order: 1,
      items: [
        {
          id: 2,
          title: '3D Assets',
          order: 1,
          items: [],
        },
        {
          id: 4,
          title: '3D Plants',
          order: 2,
          items: [],
        },
        {
          id: 3,
          title: 'Surfaces',
          order: 3,
          items: [
            {
              id: 5,
              title: 'Asphalt',
              order: 1,
              items: [],
            },
          ],
        },
      ],
    },
    {
      id: 6,
      title: 'Collections',
      order: 2,
      items: [],
      icon: '',
    },
  ];
  return (
    <div>
      {data.map((item, index) => {
        return (
          <>
            <div>{item.title}</div>
            {item.items && <ChildrenCom data={item.items}></ChildrenCom>}
          </>
        );
      })}
    </div>
  );
}

export default recursionExample;

Now below component will call till last-child, as it is called recursively

import React from 'react';

function ChildrenCom(props) {
  let {data} = props;
  return (
    <div>
      {data.map((item, index) => {
        return (
          <>
            <div>{item.title}</div>
            {item.items && <ChildrenCom data={item.items}></ChildrenCom>}
          </>
        );
      })}
    </div>
  );
}

export default ChildrenCom;

We could use Depth First Traversal to help us avoid duplication. If you're not comfortable with Depth First Traversal or Recursion, I would recommend you to go through the following snippet initially.

function dfs(item, depth = 0) {
    if (!item || Object.keys(item).length === 0) return;

    console.log("\t".repeat(depth), item.title);

    for (const subItem of item.items) {
        dfs(subItem, depth + 1);
    }
}

// Consider payload to be the response that you get from the API.
for (const item of payload)  {
    dfs(item)
}

Once you're comfortable, you could translate it into React.

const Nav = ({ item, depth = 0 }) => {
  if (!item || Object.keys(item).length === 0) return;

  return (
    <>
      <p style={{ paddingLeft: `${depth * 64}px` }}>{item.title}</p>
      {item.items.map((subItem, index) => (
        <Nav item={subItem} depth={depth + 1} />
      ))}
    </>
  );
};

export default function App() {
  return (
    <div className="App">
      {payload.map((item) => (
        <Nav item={item} />
      ))}
    </div>
  );
}

Just a simple recursive tree walk. A component like this:

const NodePropTypes = PropTypes.objectWithShape({
  id: PropTypes.number,
  title: PropTypes.string,
  items: PropTypes.array,
});
const NavListPropTypes = {
  nodes: PropTypes.arrayOf( NodePropTypes ),
};

function NavList( props ) {
  const nodes = props?.nodes ?? [];
  if (nav.length) {
    return (
      <list>
        <ListItems nodes={nodes} />
      </list>
    );
  }
}
NavList.propTypes = NavListPropTypes

function ListItems( props ) {
  const nodes = props?.nodes ?? [];
  return (
    <>
      { nodes.map( node => <ListItem node={node} /> ) }
    </>
  );
}
ListItems.propTypes = NavListPropTypes;

function ListItem( props ) {
  const node = props?.node ?? {};
  return (
    <li id={node.id} >
      <p> {node.title} </p>
      <NavList nodes={node.items} />
    </li>
  );
}
ListItem.propTypes = NodePropTypes;

which can be rendered passing your navigation response:

<NavList nodes={navigationResponse} />

And should yield something like this:

<list>
  <li id="1" >
    <p> Home </p>
    <list>
      <li id="2" >
        <p> 3D Assets </p>
      </li>
      <li id="4" >
        <p> 3d Plants </p>
      </li>
      <li id="3" >
        <p> Surfaces </p>
        <list>
          <li id="5" >
            <p> Asphalt </p>
          </li>
        </list>
      </li>
    </list>
  </li>
  <li id="6" >
    <p> Collections </p>
  </li>
</list>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM