You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌套对象转HTML树形表格问题:父节点重复且不符预期

问题:嵌套对象转HTML表格时父节点重复,树形结构不符合预期

我需要把嵌套对象映射成HTML表格,实现父子数据的树形结构,但现在的结果里父节点重复,而且树形数据没达到预期效果。

当前输出结果

ID  Name
1   A.1
1.1 A.1.1
1.1.1   A.1.1.1
1.1.1.1 A.1.1.1.1
1   A.1
1.1 A.1.1
1.1.2   A.1.1.1
1.1.1.1 A.1.1.1.1
1   A.1
1.1 A.1.1
1.1.1   A.1.1.1
1.1.1.1 A.1.1.1.1
1   A.1
1.1 A.1.1
1.1.1   A.1.1.1
1.1.1.1 A.1.1.1.1
1   B.1
1.1 B.1.1
1.1.1   B.1.1.1
1.1.1.1 A.1.1.1.1
1   B.1
1.1 B.1.1
1.1.2   B.1.1.1
1.1.1.1 A.1.1.1.1
1   B.1
1.1 B.1.1
1.1.1   B.1.1.1
1.1.1.1 A.1.1.1.1
1   B.1
1.1 B.1.1
1.1.1   B.1.1.1
1.1.1.1 A.1.1.1.1

预期表格结果

| ID       | Name         |
|----------|--------------|
| "1"      | "A.1"        |
| "1.1"    | "A.1.1"      |
| "1.1.1"  | "A.1.1.1"    |
| "1.1.2"  | "A.1.1.2"    |
| "1.1.1.1"| "A.1.1.1.1"  |
| "1.1.1.1"| "A.1.1.1.2"  |
| "2"      | "B.1"        |
| "1.1"    | "B.1.1"      |
| "1.1.1"  | "B.1.1.1"    |
| "1.1.2"  | "B.1.1.2"    |
| "1.1.1.1"| "B.1.1.1.1"  |
| "1.1.1.1"| "B.1.1.1.2"  |

问题代码

import "./styles.css";

const datas = {
  A: {
    id: "1",
    name: "A.1",
    child: {
      A1: {
        id: "1.1",
        name: "A.1.1",
        child: {
          A11: {
            id: "1.1.1",
            name: "A.1.1.1",
            child: {
              A111: {
                id: "1.1.1.1",
                name: "A.1.1.1.1"
              }
            }
          },
          A12: {
            id: "1.1.2",
            name: "A.1.1.1",
            child: {
              A111: {
                id: "1.1.1.1",
                name: "A.1.1.1.1"
              }
            }
          }
        }
      },
      A2: {
        id: "1.1",
        name: "A.1.1",
        child: {
          A11: {
            id: "1.1.1",
            name: "A.1.1.1",
            child: {
              A111: {
                id: "1.1.1.1",
                name: "A.1.1.1.1"
              }
            }
          },
          A12: {
            id: "1.1.1",
            name: "A.1.1.1",
            child: {
              A111: {
                id: "1.1.1.1",
                name: "A.1.1.1.1"
              }
            }
          }
        }
      }
    }
  },
  B: {
    id: "1",
    name: "B.1",
    child: {
      B1: {
        id: "1.1",
        name: "B.1.1",
        child: {
          B11: {
            id: "1.1.1",
            name: "B.1.1.1",
            child: {
              A111: {
                id: "1.1.1.1",
                name: "A.1.1.1.1"
              }
            }
          },
          B12: {
            id: "1.1.2",
            name: "B.1.1.1",
            child: {
              A111: {
                id: "1.1.1.1",
                name: "A.1.1.1.1"
              }
            }
          }
        }
      },
      B2: {
        id: "1.1",
        name: "B.1.1",
        child: {
          B11: {
            id: "1.1.1",
            name: "B.1.1.1",
            child: {
              A111: {
                id: "1.1.1.1",
                name: "A.1.1.1.1"
              }
            }
          },
          B12: {
            id: "1.1.1",
            name: "B.1.1.1",
            child: {
              A111: {
                id: "1.1.1.1",
                name: "A.1.1.1.1"
              }
            }
          }
        }
      }
    }
  }
};

export default function App() {
  const renderRows = (parentData, dataArr = []) => {
    const newDataArr = [
      ...dataArr,
      <tr>
        <td>{parentData.id}</td>
        <td>{parentData.name}</td>
      </tr>
    ];

    if (!parentData.child) return newDataArr;
    return Object.values(parentData.child).map((child) =>
      renderRows(child, newDataArr)
    );
  };
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <table>
        <thead>
          <tr>
            <td>ID</td>
            <td>Name</td>
          </tr>
        </thead>
        <tbody>{Object.values(datas).map((data) => renderRows(data))}</tbody>
      </table>
    </div>
  );
}

解决方法

问题出在renderRows函数的递归逻辑上:每次处理子节点时,你都把当前父节点的数组newDataArr传递给每个子节点的递归调用,导致每个子节点都会重复携带父节点的所有行,最终输出大量重复内容。

正确的做法是先添加当前节点,再递归合并所有子节点的结果,而不是把当前数组传递给每个子节点。修改后的renderRows函数如下:

const renderRows = (parentData) => {
  // 先创建当前节点的行,添加key避免React警告
  const rows = [
    <tr key={`${parentData.id}-${parentData.name}`}>
      <td>{parentData.id}</td>
      <td>{parentData.name}</td>
    </tr>
  ];

  // 如果有子节点,递归处理每个子节点并合并结果
  if (parentData.child) {
    Object.values(parentData.child).forEach(child => {
      rows.push(...renderRows(child));
    });
  }

  return rows;
};

另外,你的数据源里存在一些和预期不符的字段(比如A12的name是"A.1.1.1"而不是预期的"A.1.1.2"),需要先修正数据源的错误,才能得到完全符合预期的结果:

// 修正后的部分数据源示例
A12: {
  id: "1.1.2",
  name: "A.1.1.2", // 原先是"A.1.1.1"
  child: {
    A111: {
      id: "1.1.1.1",
      name: "A.1.1.1.2" // 原先是"A.1.1.1.1"
    }
  }
}

修改后,渲染逻辑会正确遍历每个节点一次,不会重复输出父节点,同时修正数据源后就能得到你预期的表格结构。


内容的提问来源于stack exchange,提问作者rzr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 22:40:15