
Refine v5 批量删除实战使用 useDeleteMany 在 Ant Design 表格中实现多选删除【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refineuseDeleteMany是 Refine 数据层data hooks中用于一次性删除多条记录的核心 Hook本文以仓库中的table-antd-use-delete-many官方示例为主体完整讲解如何在 Ant Design 表格上实现勾选多行 → 点击删除的批量删除交互并深入packages/core源码剖析其底层实现从 dataProvider 的deleteMany调用、deleteOne降级逻辑到乐观更新、查询失效invalidate与实时通知机制。读完本文你将掌握useDeleteMany的全部参数、返回值与最佳实践并理解它在 Refine 数据流中扮演的角色。示例场景表格多选批量删除原文档 useDeleteMany.md 描述的场景非常明确useDeleteMany一次从数据库中删除多条数据而在示例中我们用它从表格里移除多条记录——用户通过勾选行选中记录点击删除按钮即可批量移除。对应示例源码位于 examples/table-antd-use-delete-many应用使用refinedev/simple-rest连接https://api.fake-rest.refine.dev这一演示 API见 App.tsx资源定义为posts包含 list / create / edit / show 四条路由。核心页面是 src/pages/posts/list.tsx。从零实现勾选、删除、刷新1. 初始化表格与分类数据页面通过useTableIPost()获取 Ant Design 表格所需的tableProps同时用useMany拉取文章关联的categories用于把category.id渲染成分类标题const { tableProps } useTableIPost(); const categoryIds tableProps?.dataSource?.map((item) item.category.id) ?? []; const { result: data, query: { isLoading }, } useManyICategory({ resource: categories, ids: categoryIds, queryOptions: { enabled: categoryIds.length 0, }, });注意这里的queryOptions.enabled当表格还没有数据时categoryIds为空数组此时禁用该查询避免发无意义的请求。2. 调用 useDeleteMany 并执行删除这是整页的核心const { mutate, mutation: { isPending: deleteManyIsLoading }, } useDeleteManyIPost(); const deleteSelectedItems () { mutate( { resource: posts, ids: selectedRowKeys.map(String), }, { onSuccess: () { setSelectedRowKeys([]); }, }, ); };要点解析mutate是触发删除的函数必填参数resource资源名对应 API 端点路径与ids要删除的记录主键数组。selectedRowKeys来自 Ant Design 的rowSelection状态map(String)确保主键统一为字符串形式传给 Hook。从mutation.isPending中解构出的deleteManyIsLoading用来驱动按钮的loading态。onSuccess回调在删除成功后清空选中状态——这正是原文档强调的useDeleteMany的mutationOptions不支持onSuccess/onError它们会被内置实现覆盖需要这类回调时请像这里一样作为mutate的第二个参数传入。3. 接入表格多选Ant Design 的Table通过rowSelection开启行勾选const [selectedRowKeys, setSelectedRowKeys] React.useStateReact.Key[]([]); const onSelectChange (selectedRowKeys: React.Key[]) { setSelectedRowKeys(selectedRowKeys); }; const rowSelection { selectedRowKeys, onChange: onSelectChange, selections: [ Table.SELECTION_ALL, Table.SELECTION_INVERT, Table.SELECTION_NONE, ], }; const hasSelected selectedRowKeys.length 0; return ( List headerProps{{ subTitle: ( Button typeprimary onClick{deleteSelectedItems} disabled{!hasSelected} loading{deleteManyIsLoading} Delete Selected /Button span style{{ marginLeft: 8 }} {hasSelected ? Selected ${selectedRowKeys.length} items : } /span / ), }} Table {...tableProps} rowSelection{rowSelection} rowKeyid {/* 列定义ID / Title / Status / Category / Actions */} /Table /List );这里有三处值得注意的细节Table.SELECTION_ALL / SELECTION_INVERT / SELECTION_NONE让表头下拉菜单支持全选 / 反选 / 取消全选。disabled{!hasSelected}保证未选中任何行时按钮不可点配合loading防止重复提交。List组件的headerProps.subTitle把操作按钮放进页面标题栏是一种整洁的布局做法。完整的列定义还包含操作列编辑、查看按钮位于 list.tsx可作为参照。批量删除的关键参数原文档将useDeleteMany定位为 TanStack QueryuseMutation的扩展版它继承useMutation的全部能力并额外增加了 Refine 的数据层能力通知、失效、实时发布等。参考 use-delete-many 文档常用参数如下参数类型默认值说明resource必填string—传给 dataProviderdeleteMany的资源名通常即 API 端点路径ids必填BaseKey[]—要删除的记录主键数组mutationModepessimistic \| optimistic \| undoablepessimistic决定变更在何时执行详见下文undoableTimeoutnumber5000毫秒undoable模式下等待执行的时长onCancel(cancelMutation) void—undoable模式下提供取消句柄定义后系统不再自动弹撤销通知successNotification/errorNotificationSuccessErrorNotification内置文案自定义成功 / 失败通知metaMetaDataQuery{}透传给 dataProvider 的附加信息如自定义请求头、GraphQL 查询dataProviderNamestringdefault存在多个 dataProvider 时指定使用哪一个invalidatesall \| resourceAll \| list \| many \| detail \| false[list, many]变更完成后要失效并重取的查询三种 mutationMode 的取舍pessimistic默认先请求后端成功后再更新界面。最保守、数据最可靠。optimistic立即在界面上移除记录请求失败时回滚缓存。undoable等待undoableTimeout毫秒默认 5 秒后才真正执行期间可撤销适合误删保护场景。这三种模式在源码测试 packages/core/src/hooks/data/useDeleteMany.spec.tsx 中均有对应用例验证详见下文测试与验证。多 dataProvider 与自定义通知示例const { mutate, mutation } useDeleteMany(); mutate({ resource: products, ids: [1, 2, 3], dataProviderName: second-data-provider, successNotification: (data, ids, resource) ({ message: ${ids.length} products deleted., description: Success with no errors, type: success, }), errorNotification: (error, ids, resource) ({ message: Something went wrong, description: error.message, type: error, }), });源码剖析useDeleteMany 的完整调用链useDeleteMany的实现位于 packages/core/src/hooks/data/useDeleteMany.ts阅读它可以把黑盒变成白盒。1. mutationFn优先 deleteMany降级 deleteOneHook 底层创建了一个 TanStack QueryuseMutationuseDeleteMany.ts其mutationFn内部通过useResourceParams的select解析resource用useDataProvider按dataProviderName选出目标 provider如果 provider 实现了deleteMany直接调用selectedDataProvider.deleteMany({ resource, ids, meta, variables })如果 provider 没有deleteMany则退化为handleMultiple(ids.map((id) deleteOne({ ... })))——即逐条调用deleteOne对每个 id 各发一次请求。原文档明确提示这是不推荐的做法最好在 dataProvider 中实现deleteMany。以refinedev/rest为例其deleteMany会按getEndpoint解析端点、buildHeaders组装请求头并对params.resource发起DELETE请求见 create-data-provider.ts。2. onMutate乐观更新与缓存快照当mutationMode ! pessimistic时onMutateuseDeleteMany.ts会用queryClient.cancelQueries取消进行中的相关查询用getQueriesData保存当前缓存快照previousQueries供失败回滚对list、many、one三类查询做本地更新——从列表数据中过滤掉被删除的 ids并把total减一。这也解释了为什么示例删除后表格自动刷新数据已经通过缓存层同步更新。3. onSettled / onSuccess / onError失效、通知与回滚onSettleduseDeleteMany.ts默认调用invalidateStore({ invalidates: [list, many] })失效列表类查询可用invalidates参数覆盖并清理 undoable 队列中的通知条目。onSuccess从缓存移除被删记录的one查询发出默认成功通知文案由notifications.deleteSuccess翻译键控制若有 Live Provider则调用publish向resources/{resource}频道发布deleted事件useDeleteMany.ts同时通过useLog记录deleteMany审计日志。onError用快照previousQueries恢复被乐观更新的缓存触发useOnError的全局错误处理并弹出默认错误通知除非错误为主动取消的mutationCancelled。4. undoable 模式实现在mutationMode undoable时mutationFn 不会立刻请求后端而是构造一个 Promise通过notificationDispatch向 undoable 队列注册cancelMutation与doMutation等待undoableTimeout秒useDeleteMany.ts倒计时结束才真正执行删除期间用户可撤销。测试与验证三种模式与 E2E 行为仓库同时提供了单元测试与端到端测试可作为实现行为的权威佐证。单元测试pessimistic / optimistic / undoablepackages/core/src/hooks/data/useDeleteMany.spec.tsx 使用MockJSONServer与TestWrapper渲染 Hookpessimisticmutate({ resource: posts, ids: [1] })后等待mutation.isSuccess为真optimisticmock 一个 1000ms 后 reject 的deleteMany先断言列表长度由 2 变为 0乐观移除请求失败后断言长度恢复为 2回滚生效undoablemutationMode: undoable, undoableTimeout: 1000下执行删除并最终成功。E2E 测试完整用户路径cypress/e2e/table-antd-use-delete-many/all.cy.ts 用 Cypress 验证了真实页面行为点击表头复选框全选后.ant-table-row-selected应恰好有 10 行未选中任何行时主按钮.ant-btn-primary应处于 disabled 状态勾选两行后点击 Delete 按钮应发出两次删除请求cy.wait(deletePost)两次。运行示例你可以通过 Refine CLI 在本地快速启动该示例npm create refine-applatest -- --example table-antd-use-delete-many示例完整源码位于 examples/table-antd-use-delete-many依赖refinedev/core、refinedev/antd与refinedev/simple-restuseDeleteMany的类型定义与实现可进一步查阅 packages/core/src/hooks/data/useDeleteMany.ts 及其配套文档 documentation/docs/data/hooks/use-delete-many/index.md。小结本文以官方table-antd-use-delete-many示例为主线完整覆盖了表格多选 批量删除的落地路径先用useTablerowSelection收集选中主键再交给useDeleteMany的mutate执行随后从源码层厘清了 Hook 的完整生命周期——deleteMany优先、deleteOne降级、乐观更新、失败回滚、查询失效、通知与实时发布。掌握了这些你便可以在自己的 Refine 应用中安全、高效地实现批量删除并依据mutationMode在数据可靠性、交互即时性与误删保护之间做出合理权衡。【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考