使用@tanstack/react-table删除表格行的状态异常问题求助
解决TanStack React Table外部按钮删除行并同步选中状态的问题
核心问题分析
- TanStack Table默认可能用行索引或内部生成ID作为
row.id,和业务数据的原始ID不一致,导致删除时选中状态和数据行不匹配 - 父组件和子组件的选中状态没有完全同步,删除后未及时清空选中状态,引发表头复选框异常、错误选中下一行的问题
解决方案步骤
1. 统一行ID为业务原始ID
在表格配置中通过getRowId指定用数据的原始ID作为行的唯一标识,确保表格内部的行ID和业务ID完全一致:
const table = useReactTable({ columns, data, getRowId: row => row.id, // 替换成你数据中的原始ID字段名 // 其他配置项 })
2. 让父组件完全控制选中状态
- 父组件维护
selectedRowIds状态(存储选中的原始ID数组),并传递给子组件 - 子组件通过
state.selectedRowIds和onSelectedRowIdsChange绑定父组件的状态,实现双向同步:
父组件代码片段
const [data, setData] = useState(initialData); const [selectedRowIds, setSelectedRowIds] = useState([]); const handleDelete = () => { // 过滤掉选中的行 const updatedData = data.filter(item => !selectedRowIds.includes(item.id)); setData(updatedData); // 清空选中状态 setSelectedRowIds([]); };
子组件AppTable配置
const table = useReactTable({ columns, data, getRowId: row => row.id, state: { selectedRowIds: props.selectedRowIds, // 绑定父组件传入的选中状态 }, onSelectedRowIdsChange: updater => { // 将表格内部的选中变更同步到父组件 props.setSelectedRowIds(updater(props.selectedRowIds)); }, getCoreRowModel: getCoreRowModel(), getSelectedRowModel: getSelectedRowModel(), })
3. 验证效果
- 删除选中行后,
selectedRowIds被清空,表格的选中状态会自动同步更新,表头复选框会恢复未选中状态 - 因为用原始ID作为行标识,删除行后不会出现下一行被错误选中的问题
完整代码示例
父组件
import { useState } from 'react'; import AppTable from './AppTable'; const initialData = [ { id: 1, name: '第一行' }, { id: 2, name: '第二行' }, { id: 3, name: '第三行' }, ]; export default function ParentComponent() { const [data, setData] = useState(initialData); const [selectedRowIds, setSelectedRowIds] = useState([]); const handleDelete = () => { setData(prevData => prevData.filter(item => !selectedRowIds.includes(item.id))); setSelectedRowIds([]); }; return ( <div style={{ padding: '20px' }}> <button onClick={handleDelete} style={{ marginBottom: '10px' }}> 删除选中行 </button> <AppTable data={data} selectedRowIds={selectedRowIds} setSelectedRowIds={setSelectedRowIds} /> </div> ); }
子组件AppTable
import { useReactTable, getCoreRowModel, getSelectedRowModel, flexRender } from '@tanstack/react-table'; export default function AppTable({ data, selectedRowIds, setSelectedRowIds }) { const columns = [ { id: 'select', header: ({ table }) => ( <input type="checkbox" checked={table.getIsAllRowsSelected()} onChange={table.getToggleAllRowsSelectedHandler()} /> ), cell: ({ row }) => ( <input type="checkbox" checked={row.getIsSelected()} onChange={row.getToggleSelectedHandler()} /> ), }, { accessorKey: 'name', header: '行名称', }, ]; const table = useReactTable({ columns, data, getRowId: row => row.id, state: { selectedRowIds, }, onSelectedRowIdsChange: updater => { setSelectedRowIds(updater(selectedRowIds)); }, getCoreRowModel: getCoreRowModel(), getSelectedRowModel: getSelectedRowModel(), }); return ( <table border="1" cellPadding="8"> <thead> {table.getHeaderGroups().map(headerGroup => ( <tr key={headerGroup.id}> {headerGroup.headers.map(header => ( <th key={header.id}> {flexRender(header.column.columnDef.header, header.getContext())} </th> ))} </tr> ))} </thead> <tbody> {table.getRowModel().rows.map(row => ( <tr key={row.id}> {row.getVisibleCells().map(cell => ( <td key={cell.id}> {flexRender(cell.column.columnDef.cell, cell.getContext())} </td> ))} </tr> ))} </tbody> </table> ); }
内容的提问来源于stack exchange,提问作者Yuri Dukhanin
相关产品推荐
相关产品推荐

