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

React中动态映射表头与行时表头重复问题排查

问题描述

我获取到如下结构的JSON响应数据:

[
    {
        "DESCRIPTION": "OER",
        "OER_HI": 23.23650286618332,
        "OER_BI": 23.419567144988942,
        "OER_SBI": 23.74404977161088
    },
    {
        "DESCRIPTION": "CPO Production",
        "OER_HI": 1046.17,
        "OER_BI": 10538.517,
        "OER_SBI": 87788.887
    },
    {
        "DESCRIPTION": "CPO Dispatch",
        "OER_HI": 1489.6000000000001,
        "OER_BI": 9145.67,
        "OER_SBI": 81187.22
    },
    {
        "DESCRIPTION": "CPO Stock",
        "OER_HI": 12032.43,
        "OER_BI": null,
        "OER_SBI": null
    },
    {
        "DESCRIPTION": "Total Oil, Losses/FFB",
        "OER_HI": 1.4761952,
        "OER_BI": 1.4469707631313098,
        "OER_SBI": 1.44239404903668
    }
]

我期望在React中动态映射生成表头为JSON键、表行为对应值的表格,但使用以下代码实现后,表头出现重复的JSON键值,请问代码中存在什么问题?

import React, {useEffect} from "react";
import {connect, useDispatch} from "react-redux";
import {Table, Header} from "semantic-ui-react";
import {fetchChart8} from "../redux/actions";
import LoadingStatus from "./templates/LoadingStatus";
import _ from "lodash"

const TableChart = ({chart_8}) => {
    const dispatch = useDispatch();

    let testMap = chart_8?.map(data => {
        return Object.keys(data)
    })

    let description = testMap[0]
    let oer_hi = testMap[0]
    let oer_bi = testMap[0]
    let oer_sbi = testMap[0]

    useEffect(() => {

        dispatch(fetchChart8())

    }, [dispatch]);


    if (_.isNull(chart_8)) return <LoadingStatus/>;

    return (
        <div>
            <Header>
                <Header.Content>CPO</Header.Content>
            </Header>
            <Table celled>
                <Table.Header>
                    <Table.Row>
                        <Table.HeaderCell>
                            {description}
                        </Table.HeaderCell>
                        <Table.HeaderCell>
                            {oer_hi}
                        </Table.HeaderCell>
                        <Table.HeaderCell>
                            {oer_bi}
                        </Table.HeaderCell>
                        <Table.HeaderCell>
                            {oer_sbi}
                        </Table.HeaderCell>
                    </Table.Row>
                </Table.Header>
                <Table.Body>
                    {chart_8.map((data) => {
                        return (
                            <Table.Row>
                                <Table.Cell>
                                    {data["DESCRIPTION"]}
                                </Table.Cell>
                                <Table.Cell>
                                    {data["OER_HI"]}
                                </Table.Cell>
                                <Table.Cell>
                                    {data["OER_BI"]}
                                </Table.Cell>
                                <Table.Cell>
                                    {data["OER_SBI"]}
                                </Table.Cell>
                            </Table.Row>
                        )
                    })}
                </Table.Body>
            </Table>
        </div>
    );
};

const mapStateToProps = (state) => {
    return {
        chart_8: state.dashboard.chart_8
    };
};

export default connect(mapStateToProps, { fetchChart8 })(TableChart);
问题分析与修复

核心问题

你的表头逻辑完全错误:

  • testMap = chart_8?.map(data => Object.keys(data)) 会生成一个二维数组,每个元素都是单条数据的完整键数组(比如每个元素都是["DESCRIPTION", "OER_HI", "OER_BI", "OER_SBI"])。
  • 你把description、oer_hi、oer_bi、oer_sbi全赋值成testMap[0]——也就是完整的键数组,这导致每个表头单元格都渲染了整个键列表,自然出现重复的键值。

修复方案

只需要取第一条数据的键数组作为表头来源,然后遍历这个数组生成表头单元格即可。如果想确保表头顺序绝对稳定,也可以手动指定键的顺序(Object.keys的顺序在ES6+是稳定的,但手动指定更可控)。

修正后的代码:

import React, { useEffect } from "react";
import { connect, useDispatch } from "react-redux";
import { Table, Header } from "semantic-ui-react";
import { fetchChart8 } from "../redux/actions";
import LoadingStatus from "./templates/LoadingStatus";
import _ from "lodash";

const TableChart = ({ chart_8 }) => {
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(fetchChart8());
  }, [dispatch]);

  if (_.isNull(chart_8)) return <LoadingStatus />;

  // 取第一条数据的键作为表头,或者手动指定顺序更可控
  const tableHeaders = chart_8.length > 0 ? Object.keys(chart_8[0]) : [];
  // 可选:手动指定表头顺序 const tableHeaders = ["DESCRIPTION", "OER_HI", "OER_BI", "OER_SBI"];

  return (
    <div>
      <Header>
        <Header.Content>CPO</Header.Content>
      </Header>
      <Table celled>
        <Table.Header>
          <Table.Row>
            {tableHeaders.map((header) => (
              <Table.HeaderCell key={header}>{header}</Table.HeaderCell>
            ))}
          </Table.Row>
        </Table.Header>
        <Table.Body>
          {chart_8.map((data, index) => (
            <Table.Row key={index}>
              {tableHeaders.map((key) => (
                <Table.Cell key={key}>
                  {data[key] ?? "-"} {/* 处理null值,用短横线替代显示 */}
                </Table.Cell>
              ))}
            </Table.Row>
          ))}
        </Table.Body>
      </Table>
    </div>
  );
};

const mapStateToProps = (state) => {
  return {
    chart_8: state.dashboard.chart_8,
  };
};

export default connect(mapStateToProps, { fetchChart8 })(TableChart);

关键优化点

  1. 直接从第一条数据提取表头键数组,遍历生成表头单元格,避免重复渲染。
  2. 表格行也通过遍历表头键生成单元格,实现完全动态,不需要硬编码每个字段。
  3. 增加data[key] ?? "-"处理null值,让表格显示更友好。
  4. 给每个动态生成的元素加上key属性,符合React列表渲染规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 19:46:01