ObjectGrid 的两套选择状态在 dispatchBulkAction 这条路径上会脱钩:工具栏消失了,行复选框还全勾着。
现状
选择状态有两个来源,必须同步移动:
selectedRows(ObjectGrid 自己的 state)—— 驱动 BulkActionBar("已选择 N 项" + 清除)
- data-table 内部的
selectedRowIds —— 驱动行复选框,只有宿主 bump selectionResetKey 时才清空(data-table.tsx:586)
富 def 那条路走 handleBulkDialogClose,两个都清:
// ObjectGrid.tsx:1797
if (result && result.succeeded > 0) {
setSelectedRows([]);
setSelectAllMatching(false);
setSelectionResetKey(k => k + 1); // ← 行复选框
setRefreshKey(k => k + 1);
}
dispatchBulkAction 的两条分支都漏了最后那半:
// ObjectGrid.tsx:1717 —— 内建/声明的批量删除
if (action === 'delete' && onBulkDelete) {
onBulkDelete(expanded);
setSelectedRows([]);
setSelectAllMatching(false); // ← 没有 setSelectionResetKey
return;
}
// ObjectGrid.tsx:1729 —— 按名字派发(消费方注册的 runner handler)
if (res?.success) {
setSelectedRows([]);
setSelectAllMatching(false); // ← 同样没有
setRefreshKey(k => k + 1);
}
于是操作成功后:工具栏消失(selectedRows 空了),但每行复选框仍然是勾选态。用户看到的是「一堆勾着的行 + 没有任何批量操作入口」,只能手动逐个取消或刷新页面。
有意思的是,handleBulkDialogClose 的注释逐字点名了这个失败模式,只是另一条路径没有遵守:
Both selection sources must move together, or the checkboxes (table-internal) and the toolbar (our selectedRows) drift out of sync — ticked rows with no toolbar.
影响面
不是回归 —— dispatchBulkAction 一直如此。#3031 / #3053 之后这条路径变窄了(能解析到对象 action 的名字现在会被提升成 def,走对话框那条正确的路),剩下两种情况仍然命中:
- 批量删除 —— 内建的
['delete'] 兜底,或作者显式写的 bulkActions: ['delete']。这是最常见的一条。
- 按名字派发 —— 消费方用
runner.registerHandler('<name>', …) 注册过、且对象没有同名 action 声明的批量操作。
建议
把两条分支都补上 setSelectionResetKey(k => k + 1),和 handleBulkDialogClose 对齐。删除分支是无条件成功语义(onBulkDelete 不回传结果),按名字那条已经在 res?.success 里了,位置现成。
值得顺手加一条断言把这个不变量钉住 —— bulkActionRefresh.test.tsx 里已经有一组同类测试("clears the row checkboxes (not just the toolbar) after a successful run"),针对的正是富 def 那条路径,照着扩到字符串/删除路径即可。
发现于 #3002 的浏览器验证过程中。
ObjectGrid的两套选择状态在dispatchBulkAction这条路径上会脱钩:工具栏消失了,行复选框还全勾着。现状
选择状态有两个来源,必须同步移动:
selectedRows(ObjectGrid 自己的 state)—— 驱动BulkActionBar("已选择 N 项" + 清除)selectedRowIds—— 驱动行复选框,只有宿主 bumpselectionResetKey时才清空(data-table.tsx:586)富 def 那条路走
handleBulkDialogClose,两个都清:dispatchBulkAction的两条分支都漏了最后那半:于是操作成功后:工具栏消失(
selectedRows空了),但每行复选框仍然是勾选态。用户看到的是「一堆勾着的行 + 没有任何批量操作入口」,只能手动逐个取消或刷新页面。有意思的是,
handleBulkDialogClose的注释逐字点名了这个失败模式,只是另一条路径没有遵守:影响面
不是回归 ——
dispatchBulkAction一直如此。#3031 / #3053 之后这条路径变窄了(能解析到对象 action 的名字现在会被提升成 def,走对话框那条正确的路),剩下两种情况仍然命中:['delete']兜底,或作者显式写的bulkActions: ['delete']。这是最常见的一条。runner.registerHandler('<name>', …)注册过、且对象没有同名 action 声明的批量操作。建议
把两条分支都补上
setSelectionResetKey(k => k + 1),和handleBulkDialogClose对齐。删除分支是无条件成功语义(onBulkDelete不回传结果),按名字那条已经在res?.success里了,位置现成。值得顺手加一条断言把这个不变量钉住 ——
bulkActionRefresh.test.tsx里已经有一组同类测试("clears the row checkboxes (not just the toolbar) after a successful run"),针对的正是富 def 那条路径,照着扩到字符串/删除路径即可。发现于 #3002 的浏览器验证过程中。