React中Mantine表格行分组报错:存在重复key
解决Mantine表格行分组的重复Key错误及实现预期效果
问题原因
- 重复Key错误:
<tbody>里的每个<td>都用d.state_name作为key,同一行内多个td共享相同key,违反React对key唯一性的要求<thead>和<tbody>中的<tr>未设置唯一key,也会触发警告
- 行分组逻辑未生效:你定义的
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
相关产品推荐
相关产品推荐

