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

React中ShanCN Table删除行时rowSelection状态累加问题求助

TanStack Table(ShanCN Table)删除行后选中状态累加问题排查与解决

问题场景

使用基于TanStack Table的ShanCN Table实现部门行删除功能,通过selectedRows钩子获取选中行索引,将setSelectedRows作为props传给表格组件。前两三次删除操作正常,但后续删除时,rowSelection状态会保留之前的选中值并累加——例如删除行索引['1']后,再选中行2删除时,rowSelection的值变为['1','2'],而非预期的['2']。尝试用useCallback优化但无效,怀疑是闭包和异步特性导致。

相关代码

const DepartmentsAndRolesPage = () => {
  const [departments, setDepartments] = useState<departmentTypes[]>([]);
  const [selectedRows, setSelectedRows] = useState({});
  const [rowIndexes, setRowIndexes] = useState<string[]>([]);

  useEffect(() => {
    getDepartment();
  }, []);

  useEffect(() => {
    const indexesToAdd = Object.keys(selectedRows);
    setRowIndexes(indexesToAdd);
  }, [selectedRows]);

  const deleteDepartment = useCallback(async () => {

    if (rowIndexes.length === 0) {
      return;
    }

    if (rowIndexes.length === 1) {
      const filteredDepartment = departments[parseInt(rowIndexes[0])];
      const id = filteredDepartment._id;
      const response = await axios.delete(`/api/department/delete/${id}`);
      if (response.statusText === "OK") {
        getDepartment();
        setSelectedRows({});
      }
      return;
    }

    if (rowIndexes.length > 1) {
      const departmentsToDelete = rowIndexes.map(
        (rowIndex) => departments[parseInt(rowIndex)]._id
      );
      const response = await axios.post("/api/department/delete", {
        _id: departmentsToDelete,
      });
      if (response.statusText === "OK") {
        getDepartment();
        setSelectedRows({});
      }
      return;
    }
  }, [departments, rowIndexes, toast]);

  return (/* UI代码 */)
};

问题原因

  1. 行索引的不稳定性:删除行后,表格剩余行的索引会发生偏移,而TanStack Table的rowSelection默认绑定行在原始数据中的索引。当旧索引被删除后,新行索引和之前的选中状态产生映射混乱,导致选中状态无法正确重置。
  2. 闭包与异步状态更新:deleteDepartment中依赖的departments和rowIndexes是闭包捕获的旧值,异步请求完成后调用setSelectedRows({})时,可能因状态更新的异步性,导致表格组件未及时同步最新选中状态,进而出现累加问题。

解决方案

方案1:改用行数据的唯一ID作为选中标识(已验证有效)

放弃使用行索引作为选中依据,改用行数据的_id(唯一标识)绑定选中状态:

  • 在表格配置中,设置rowSelection的idAccessor为row => row._id,让选中状态绑定行的唯一ID而非索引。
  • 删除操作时,直接从selectedRows中提取选中的_id,无需依赖行索引,彻底避免索引偏移带来的问题。

方案2:优化现有代码逻辑(若坚持使用行索引)

  1. 用函数式更新清空选中状态:确保在getDepartment完成后,拿到最新状态进行清空:
    setSelectedRows(prev => ({}));
    
  2. 减少中间状态依赖:直接在deleteDepartment中从selectedRows提取索引,省去rowIndexes中间状态,降低闭包捕获旧值的概率:
    const deleteDepartment = useCallback(async () => {
      const selectedIndexes = Object.keys(selectedRows);
      if (selectedIndexes.length === 0) return;
      // 后续逻辑改用selectedIndexes替代rowIndexes
    }, [departments, selectedRows, toast]);
    
  3. 强制同步数据与选中状态:在getDepartment获取最新数据后,立即清空选中状态,因为旧索引在新数据中已失效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 13:07:37