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

ReactJS中如何从嵌套对象提取键值对并生成动态树形表格?

React 树形层级动态表格实现方案

核心思路

  • 用数组expandedNodes记录所有展开的节点路径,控制层级展开/收起
  • 通过节点路径解析API嵌套数据,实现分层渲染
  • 根据选中的节点类型(Apps/Hardware),动态生成对应结构的表格

完整代码实现

import { useState } from 'react';

// 模拟API返回的嵌套结构数据
const apiData = {
  HPC: {
    ADAS: {
      Apps: [
        { id: 1, name: 'ADAS感知', version: 'v2.3', status: '运行中' },
        { id: 2, name: '路径规划', version: 'v1.8', status: '待部署' }
      ],
      Hardware: [
        { id: 1, model: 'NVIDIA Xavier', serial: 'XAV-001', usage: '75%' },
        { id: 2, model: 'Intel Xeon', serial: 'XEON-003', usage: '60%' }
      ]
    },
    CP: {
      Apps: [
        { id: 1, name: '车辆控制', version: 'v3.1', status: '运行中' },
        { id: 2, name: '故障诊断', version: 'v2.5', status: '运行中' }
      ],
      Hardware: [
        { id: 1, model: 'TI TDA4VM', serial: 'TDA-007', usage: '80%' }
      ]
    }
  }
};

const HierarchicalTable = () => {
  // 存储展开的节点路径,格式如 ['HPC', 'HPC.ADAS']
  const [expandedNodes, setExpandedNodes] = useState([]);
  // 存储当前要展示表格的节点路径
  const [activeTableNode, setActiveTableNode] = useState(null);

  // 切换节点展开/收起状态
  const toggleNode = (nodePath) => {
    setExpandedNodes(prev => 
      prev.includes(nodePath)
        ? prev.filter(path => path !== nodePath)
        : [...prev, nodePath]
    );
    // 展开新节点时清空当前表格选中状态
    if (!expandedNodes.includes(nodePath)) {
      setActiveTableNode(null);
    }
  };

  // 触发表格展示/隐藏
  const showTable = (nodePath) => {
    setActiveTableNode(prev => prev === nodePath ? null : nodePath);
  };

  // 根据节点路径获取对应数据
  const getDataByPath = (path) => {
    return path.split('.').reduce((data, key) => data?.[key], apiData);
  };

  // 递归渲染树形按钮层级
  const renderTree = (data, parentPath = '') => {
    return Object.keys(data).map(key => {
      const currentPath = parentPath ? `${parentPath}.${key}` : key;
      const isExpanded = expandedNodes.includes(currentPath);
      const hasChildren = typeof data[key] === 'object' && !Array.isArray(data[key]);

      return (
        <div key={currentPath} style={{ marginLeft: parentPath ? '20px' : 0, marginTop: '10px' }}>
          <button
            onClick={() => hasChildren ? toggleNode(currentPath) : showTable(currentPath)}
            style={{ padding: '8px 16px', cursor: 'pointer', background: '#f0f0f0', border: '1px solid #ddd', borderRadius: '4px' }}
          >
            {isExpanded ? '▼' : '▶'} {key}
          </button>
          {/* 渲染子节点 */}
          {isExpanded && hasChildren && renderTree(data[key], currentPath)}
          {/* 渲染对应表格 */}
          {activeTableNode === currentPath && renderTable(data[key])}
        </div>
      );
    });
  };

  // 渲染Apps/Hardware表格
  const renderTable = (tableData) => {
    if (!tableData?.length) return null;

    // 根据数据字段判断表格类型,生成对应表头
    const isAppsTable = 'name' in tableData[0];
    const tableHeaders = isAppsTable
      ? ['ID', '应用名称', '版本', '状态']
      : ['ID', '硬件型号', '序列号', '使用率'];

    return (
      <div style={{ marginLeft: '40px', marginTop: '10px' }}>
        <table style={{ borderCollapse: 'collapse', width: '80%' }}>
          <thead>
            <tr>
              {tableHeaders.map(header => (
                <th key={header} style={{ border: '1px solid #ddd', padding: '8px', background: '#f5f5f5', textAlign: 'left' }}>
                  {header}
                </th>
              ))}
            </tr>
          </thead>
          <tbody>
            {tableData.map(item => (
              <tr key={item.id}>
                <td style={{ border: '1px solid #ddd', padding: '8px' }}>{item.id}</td>
                {isAppsTable ? (
                  <>
                    <td style={{ border: '1px solid #ddd', padding: '8px' }}>{item.name}</td>
                    <td style={{ border: '1px solid #ddd', padding: '8px' }}>{item.version}</td>
                    <td style={{ border: '1px solid #ddd', padding: '8px' }}>{item.status}</td>
                  </>
                ) : (
                  <>
                    <td style={{ border: '1px solid #ddd', padding: '8px' }}>{item.model}</td>
                    <td style={{ border: '1px solid #ddd', padding: '8px' }}>{item.serial}</td>
                    <td style={{ border: '1px solid #ddd', padding: '8px' }}>{item.usage}</td>
                  </>
                )}
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    );
  };

  return (
    <div style={{ padding: '20px' }}>
      {renderTree(apiData)}
    </div>
  );
};

export default HierarchicalTable;

关键细节说明

  • 层级状态控制:expandedNodes数组精准记录每个展开的节点路径,避免状态混乱
  • 路径解析逻辑:通过split('.')和reduce方法,轻松从嵌套API数据中定位目标内容
  • 表格自适应:根据数据字段自动匹配表头和列内容,无需硬编码多套表格组件
  • 样式优化:通过内联样式实现层级缩进和标准表格边框,确保展示清晰整洁

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 07:17:01