从多级嵌套对象数组 reactjs 创建嵌套的 JSX 列表项

IT技术 javascript reactjs
2021-05-03 01:18:13

我正在尝试从嵌套对象数组创建嵌套的 JSX 列表项。下面是数组:

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

以下是数组应转换为的内容:

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

这是我的方法:

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 不允许将单个标记添加到数组中。请帮忙提供解决方案。
PS:如果您发现格式有问题,我提前道歉。这是我第一次在 stackOverflow 上发帖。

4个回答

您可以将您的孩子“渲染”成一个变量并直接在您的组件中使用它。诀窍是使用递归组件。这样,你的树有多深都没有关系。如果您的树变得更深,则不需要编辑此组件。

这可能是这样的:

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>
  );
}

这是使用您的数据Codesandbox上的一个工作示例

您应该一次将整个节点推送到阵列。有一个这样的渲染方法。

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>
  );
};

并在您的渲染函数中使用数据调用该方法

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

export default Layout;

这是一个使用 stencil 的完整解决方案示例,它是一个在语法上类似于 React 的框架。您可以使用Array.prototype.reduce.

import { Component, State } from '@stencil/core';

@Component({
    tag: 'app-nested-list-demo'
})
export class NestedList {

    @State() foo = [
        {
            name: 'US',
            makers: [
                {
                    name: 'Ford',
                    models: [
                        {
                            name: 'Suburban',
                            mpg: '9000'
                        },
                        {
                            name: 'Escape',
                            mpg: '300'
                        }
                    ]
                },
                {
                    name: 'GMC',
                    models: [
                        {
                            name: 'Acadia',
                            mpg: '11'
                        },
                        {
                            name: 'Envoy',
                            mpg: 'Yukon'
                        }
                    ]
                }
            ]
        },
        {
            name: 'Japan',
            makers: [
                {
                    name: 'Honda',
                    models: [
                        {
                            name: 'CRV',
                            mpg: '100'
                        },
                        {
                            name: 'Accord',
                            mpg: '9000'
                        }
                    ]
                },
                {
                    name: 'Toyota',
                    models: [
                        {
                            name: 'Rav4',
                            mpg: '10'
                        },
                        {
                            name: 'Camry',
                            mpg: '400'
                        }
                    ]
                }
            ]
        }
    ];

    render() {
        const outerList = this.foo.map(country => {

            const middleList = country.makers.map(make => {

                const innerList = make.models.map(model => {
                    return (
                        <li>{model.name} has {model.mpg} MPG</li>
                    );
                });

                return (
                    <li>
                        {make.name}
                        <ul>
                            {innerList}
                        </ul>
                    </li>
                );

            });

            return (
                <li>
                    {country.name}
                    <ul>
                        {middleList}
                    </ul>
                </li>
            );
        });

        return (
            <ul>
                {outerList}
            </ul>
        );

    }
}

我问了同样的问题,但我已经有了一个脚本,所以我只是在寻找一个更简单的解决方案。这里的脚本可能会有所帮助。

//基于嵌套数组渲染一个嵌套元素