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

React中Mantine表格行分组报错:存在重复key

解决Mantine表格行分组的重复Key错误及实现预期效果

问题原因

  1. 重复Key错误:
    • <tbody>里的每个<td>都用d.state_name作为key,同一行内多个td共享相同key,违反React对key唯一性的要求
    • <thead>和<tbody>中的<tr>未设置唯一key,也会触发警告
  2. 行分组逻辑未生效:你定义的column配置里的render方法完全没被使用,手动渲染td的方式没有结合rowspan合并逻辑

修正步骤

1. 预处理数据,标记行分组信息

遍历原始数据,记录每个州的首次出现位置及需要合并的行数,方便后续渲染时控制单元格显示:

// 预处理数据,添加行分组标记
const processedData = data.reduce((acc, item) => {
  const sameStateExists = acc.some(prev => prev.state_name === item.state_name);
  if (sameStateExists) {
    return [...acc, { ...item, showState: false }];
  }
  const stateCount = data.filter(d => d.state_name === item.state_name).length;
  return [...acc, { ...item, showState: true, stateRowSpan: stateCount }];
}, [] as (typeof data[0] & { showState: boolean; stateRowSpan?: number })[]);

2. 修正Key唯一性问题

  • 给<tbody>的每个<tr>设置唯一key,比如结合state_name和gender(同一州下gender唯一)
  • 给每个<td>设置唯一key,采用行标识-列标识的组合形式

3. 实现行分组的跨行合并

根据预处理的showState标记控制州名单元格的显示,同时通过rowSpan属性实现跨行合并

完整修正代码

import { Table } from "@mantine/core";

export const Demo = () => {
  const data = [
    { state_name: "Karnataka", gender: "Boys", total: Math.floor(Math.random() * 90 + 10), passed_total: Math.floor(Math.random() * 90 + 10) },
    { state_name: "Karnataka", gender: "Girls", total: Math.floor(Math.random() * 90 + 10), passed_total: Math.floor(Math.random() * 90 + 10) },
    { state_name: "Karnataka", gender: "Transgender", total: Math.floor(Math.random() * 90 + 10), passed_total: Math.floor(Math.random() * 90 + 10) },
    { state_name: "Kerala", gender: "Boys", total: Math.floor(Math.random() * 90 + 10), passed_total: Math.floor(Math.random() * 90 + 10) },
    { state_name: "Kerala", gender: "Girls", total: Math.floor(Math.random() * 90 + 10), passed_total: Math.floor(Math.random() * 90 + 10) },
    { state_name: "Tamilnadu", gender: "Boys", total: Math.floor(Math.random() * 90 + 10), passed_total: Math.floor(Math.random() * 90 + 10) },
    { state_name: "Tamilnadu", gender: "Girls", total: Math.floor(Math.random() * 90 + 10), passed_total: Math.floor(Math.random() * 90 + 10) },
    { state_name: "Andhra Pradesh", gender: "Boys", total: Math.floor(Math.random() * 90 + 10), passed_total: Math.floor(Math.random() * 90 + 10) },
  ];

  // 预处理数据,添加行分组标记
  const processedData = data.reduce((acc, item) => {
    const sameStateExists = acc.some(prev => prev.state_name === item.state_name);
    if (sameStateExists) {
      return [...acc, { ...item, showState: false }];
    }
    const stateCount = data.filter(d => d.state_name === item.state_name).length;
    return [...acc, { ...item, showState: true, stateRowSpan: stateCount }];
  }, [] as (typeof data[0] & { showState: boolean; stateRowSpan?: number })[]);

  return (
    <Table withBorder withColumnBorders style={{ width: "50%", margin: "0 auto", marginTop: "50px" }}>
      <thead>
        <tr>
          <th>District</th>
          <th>Gender Details</th>
          <th>Total number of candidates</th>
          <th>Total Number of candidates passed</th>
        </tr>
      </thead>
      <tbody>
        {processedData.map((d) => {
          const rowKey = `${d.state_name}-${d.gender}`;
          return (
            <tr key={rowKey}>
              {/* 州名列:仅首次出现时显示,并设置跨行合并 */}
              {d.showState ? (
                <td key={`${rowKey}-state`} rowSpan={d.stateRowSpan}>
                  {d.state_name}
                </td>
              ) : null}
              <td key={`${rowKey}-gender`}>{d.gender}</td>
              <td key={`${rowKey}-total`}>{d.total}</td>
              <td key={`${rowKey}-passed`}>{d.passed_total}</td>
            </tr>
          );
        })}
      </tbody>
    </Table>
  );
};

关键说明

  • 预处理数据时,用showState标记是否需要显示州名,stateRowSpan记录该州需要合并的行数
  • 所有<tr>和<td>都设置了唯一key,彻底解决重复key错误
  • 通过rowSpan属性实现单元格跨行合并,达到预期的行分组视觉效果

内容的提问来源于stack exchange,提问作者Aishwarya J S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 22:45:29