reactjs 递归函数,用于重构对象内部的数组

l7wslrjt  于 2023-03-01  发布在  React
关注(0)|答案(1)|浏览(104)

我目前正在处理显示表格。
但是我卡住了,因为数据结构是超级嵌套的。这是原始结构:

{
      "key": "parent_table",
      "title": "parent_table",
      "type": "table",
      "children": [
        {
          "key": "parent_record[0]",
          "title": "parent_record[0]",
          "children": [
            {
              "key": "parent_field_1",
              "title": "parent_field_1",
              "type": "input",
              "children": [
                {
                  "key": "parent_field_1_value",
                  "title": "parent_field_1_value",
                  "value": "2122",
                  "type": "input"
                }
              ]
            },
            {
              "key": "parent_field_2",
              "title": "parent_field_2",
              "type": "table",
              "children": [
                {
                  "key": "children_1_table",
                  "title": "tablerow[1]",
                  "children": [
                    {
                      "key": "column1",
                      "title": "column1",
                      "type": "input",
                      "children": [
                        {
                          "key": "column1_value",
                          "title": "column1_value",
                          "value": "column1_value",
                          "type": "input"
                        }
                      ]
                    },
                    {
                      "key": "column2",
                      "title": "column2",
                      "type": "input",
                      "children": [
                        {
                          "key": "column2_value",
                          "title": "column2_value",
                          "value": "column2_value",
                          "type": "input"
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          "key": "parent_record[1]",
          "title": "parent_record[1]",
          "children": [
            {
              "key": "parent_field_1",
              "title": "parent_field_1",
              "type": "input",
              "children": [
                {
                  "key": "parent_field_1_value",
                  "title": "parent_field_1_value",
                  "value": "2122",
                  "type": "input"
                }
              ]
            },
            {
              "key": "parent_field_2",
              "title": "parent_field_2",
              "type": "table",
              "children": [
                {
                  "key": "children_2_table",
                  "title": "tablerow[1]",
                  "children": [
                    {
                      "key": "column1",
                      "title": "column1",
                      "type": "input",
                      "children": [
                        {
                          "key": "column1_value",
                          "title": "column1_value",
                          "value": "column1_value",
                          "type": "input"
                        }
                      ]
                    },
                    {
                      "key": "column2",
                      "title": "column2",
                      "type": "input",
                      "children": [
                        {
                          "key": "column2_value",
                          "title": "column2_value",
                          "value": "column2_value",
                          "type": "input"
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }

这是预期的数据结构:

[
  {
    "key": "parent_table",
    "title": "parent_table",
    "type": "table",
    "children": [
      {
        "key": "parent_record[0]",
        "title": "parent_record[0]",
        "children": [
          {
            "key": "parent_field_1",
            "title": "parent_field_1",
            "type": "input",
            "children": [
              {
                "key": "parent_field_1_value",
                "title": "parent_field_1_value",
                "value": "2122",
                "type": "input"
              }
            ]
          }
        ]
      },
      {
        "key": "parent_record[1]",
        "title": "parent_record[1]",
        "children": [
          {
            "key": "parent_field_1",
            "title": "parent_field_1",
            "type": "input",
            "children": [
              {
                "key": "parent_field_1_value",
                "title": "parent_field_1_value",
                "value": "2122",
                "type": "input"
              }
            ]
          }
        ]
      }
    ]
  },
  {
    "key": "parent_field_2",
    "title": "parent_field_2",
    "type": "table",
    "children": [
      {
        "key": "children_1_table",
        "title": "tablerow[1]",
        "children": [
          {
            "key": "column1",
            "title": "column1",
            "type": "input",
            "children": [
              {
                "key": "column1_value",
                "title": "column1_value",
                "value": "column1_value",
                "type": "input"
              }
            ]
          },
          {
            "key": "column2",
            "title": "column2",
            "type": "input",
            "children": [
              {
                "key": "column2_value",
                "title": "column2_value",
                "value": "column2_value",
                "type": "input"
              }
            ]
          }
        ]
      }
    ]
  },
  {
    "key": "parent_field_2",
    "title": "parent_field_2",
    "type": "table",
    "children": [
      {
        "key": "children_2_table",
        "title": "tablerow[1]",
        "children": [
          {
            "key": "column1",
            "title": "column1",
            "type": "input",
            "children": [
              {
                "key": "column1_value",
                "title": "column1_value",
                "value": "column1_value",
                "type": "input"
              }
            ]
          },
          {
            "key": "column2",
            "title": "column2",
            "type": "input",
            "children": [
              {
                "key": "column2_value",
                "title": "column2_value",
                "value": "column2_value",
                "type": "input"
              }
            ]
          }
        ]
      }
    ]
  }
]

基本上,递归函数将从父表中拉出子表,并使子表与父表处于同一层。

ztyzrc3y

ztyzrc3y1#

为了便于在TypeScript中使用,让我们定义递归Tree类型如下:

interface Tree {
  key: string;
  title: string;
  value?: string;
  type?: string;
  children?: Tree[]
}

你想用下面的调用签名写一个函数:

declare function extractTables(tree: Tree): Tree[]

所以它接受一个Tree,并产生一个Tree数组,对应于树中某个地方的所有"table"类型的树元素,我假设您不想实际 * 改变 * 输入树,所以我们必须在更改任何内容之前进行复制。
这里的一般方法是:我们将递归地遍历树,做两件事:生成一个适合在输出中出现的当前树节点的修改版本,并从当前子树中收集所有修改过的表树节点。最后,我们只需要修改过的表树节点集,所以我们将用一个函数来 Package 树遍历器,该函数在最后丢弃"当前"节点。
它看起来像这样:

function extractTables(tree: Tree) {
  interface WalkResult {
    tables: Tree[],
    modified: Tree
  }
  function walk(tree: Tree): WalkResult {
    const { children, ...base } = tree;
    const tables: Tree[] = [];
    let modifiedChildren: Tree[] | undefined;
    if (children) {
      const walkedChildren = children.map(walk);
      modifiedChildren = walkedChildren
        .filter(wr => wr.modified.type !== "table")
        .map(wr => wr.modified);
      walkedChildren
        .forEach(wr => tables.push(...wr.tables));
    }
    const modified = { ...base, ...children && { children: modifiedChildren } };
    if (modified.type === "table") tables.unshift(modified);
    return { tables, modified };
  }
  return walk(tree).tables;
}

所以内部的walk()函数是递归的,返回一个WalkResultextractTables()返回walk(tree)tables属性。
walk()函数本身必须获取当前节点和在其所有children(如果存在)上运行walkWalkResult,并为当前节点生成WalkResult
它首先将当前节点拆分为children属性和其他所有属性(使用destructuring assignment)。
如果当前节点有children,那么我们递归walk每个子节点。当前修改的节点需要修改的children。它是通过收集每个非"table"修改的子元素而形成的。在children中遇到的每个tables集合都应该连接在一起,并用于返回的tables(如果没有children,则该表列表为空)。
我们通过将非children属性和修改后的children属性重新相加来构建当前修改后的节点如果当前节点是一个table,那么我们需要把它前置到我们从子节点构建的表列表中,现在我们有了一个当前修改的节点和一个当前修改的表节点列表,这样我们就可以返回我们的WalkResult
就这样,我们结束了。
我们可以检查示例输入的extractTables(input)是否产生了与示例输出相同的结构:

console.log(JSON.stringify(output) === JSON.stringify(expectedOutput)); // true

确实如此!
Playground代码链接

相关问题