ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Refine v5 Mantine `<DeleteButton>` 组件完全指南:删除确认、权限控制与底层 useDelete 机制

Refine v5 Mantine `<DeleteButton>` 组件完全指南:删除确认、权限控制与底层 useDelete 机制 Refine v5 MantineDeleteButton组件完全指南删除确认、权限控制与底层 useDelete 机制【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine导读DeleteButton是 Refine v5 在 Mantine UI 集成中提供的删除操作按钮它在 refinedev/mantine 包中实现底层由 Mantine 的Button与Popover组合而成点击后弹出确认气泡确认后才真正执行删除。本文以官方文档 documentation/docs/ui-integrations/mantine/components/buttons/delete-button/index.md 为主体结合packages/mantine、packages/core、packages/ui-types、packages/ui-tests中的源码完整讲解该组件的使用方式、全部核心属性、底层删除链路useDeleteButton→useDelete→dataProvider.deleteOne以及权限控制、缓存失效等进阶主题。读完本文你将能在任意 Refine Mantine 项目中安全、规范地接入删除操作并理解其背后的完整执行流程。组件定位一条内置安全删除流程的按钮DeleteButton的核心设计目标是为破坏性操作增加一道确认屏障。从源码注释packages/mantine/src/components/buttons/delete/index.tsx#L13-L18可以看到DeleteButtonuses MantineButtonandModalcomponents. When you try to delete something, a dialog modal shows up and asks for confirmation. When confirmed it executes theuseDeletemethod provided by yourdataProvider.实际实现中确认交互使用的是 Mantine 的Popover而非Modal按钮作为Popover.Target确认区域位于Popover.Dropdown内包含提示标题、取消按钮与确认按钮packages/mantine/src/components/buttons/delete/index.tsx#L70-L135。工作流程为用户点击删除按钮Popover 展开气泡中显示确认标题默认Are you sure?以及Cancel / Delete两个按钮点击确认后调用由 useDeleteButton hook 提供的onConfirm进而触发useDelete的mutateuseDelete将参数透传给dataProvider的deleteOne方法完成真实的数据删除。同时Refine 提供了swizzle 机制你可以通过 Refine CLI 的swizzle命令把该组件弹出到项目src/components/目录下自由定制官方文档原文提示You can swizzle this component with the Refine CLI to customize it.。执行npm run refine swizzle后按交互提示选择refinedev/mantine包与DeleteButton组件即可。基础用法在列表页中为每一行挂载删除按钮最典型的使用场景是在表格的 Actions 列中为每条记录渲染一个删除按钮。官方文档给出了基于refinedev/react-tabletanstack/react-table的完整示例其核心片段如下import { List, DeleteButton } from refinedev/mantine; import { Table, Pagination } from mantine/core; import { useTable } from refinedev/react-table; import { ColumnDef, flexRender } from tanstack/react-table; const PostList: React.FC () { const columns React.useMemoColumnDefIPost[]( () [ { id: id, header: ID, accessorKey: id, }, { id: title, header: Title, accessorKey: title, }, { id: actions, header: Actions, accessorKey: id, cell: function render({ getValue }) { return ( // 关键将当前行的 id 传给 recordItemId DeleteButton sizexs recordItemId{getValue() as number} / ); }, }, ], [], ); const { reactTable: { getHeaderGroups, getRowModel }, refineCore: { setCurrentPage, pageCount, currentPage }, } useTable({ columns }); return ( List Table thead {getHeaderGroups().map((headerGroup) ( tr key{headerGroup.id} {headerGroup.headers.map((header) ( th key{header.id} {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())} /th ))} /tr ))} /thead tbody {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 br / Pagination positionright total{pageCount} page{currentPage} onChange{setCurrentPage} / /List ); }; interface IPost { id: number; title: string; }这个模式在仓库的真实示例中大量使用。例如 examples/form-mantine-use-form/src/pages/posts/list.tsx#L86-L101 中ShowButton、EditButton、DeleteButton被组合放在Group spacingxs noWrap中并且统一使用了hideText属性来压缩行高cell: function render({ getValue }) { return ( Group spacingxs noWrap ShowButton hideText recordItemId{getValue() as number} / EditButton hideText recordItemId{getValue() as number} / DeleteButton hideText recordItemId{getValue() as number} / /Group ); },核心属性详解官方文档以recordItemId、resource、onSuccess、hideText为主线展开同时底层类型 RefineDeleteButtonProps 还暴露了更多面向数据与权限的配置。下面逐一说明。recordItemId指定要删除的记录recordItemId决定删除哪一条记录。默认情况下它从当前路由参数URL 中的:id读取在edit/show详情页中这通常正是你想要的。在列表页中则需要像上面的示例一样显式传入每行的 idimport { DeleteButton } from refinedev/mantine; const MyDeleteComponent () { return DeleteButton recordItemId123 /; };点击按钮并确认后会触发useDelete方法删除resource为当前路由资源、id为123的记录。类型定义中该属性的注释为 Data item identifier for the actions with the API默认值注释为 Reads:idfrom the URLpackages/ui-types/src/types/button.tsx#L41-L47。resource指定删除的资源resource决定删除哪个资源下的记录。默认从当前路由推断需要操作非当前路由的资源时显式传入import { DeleteButton } from refinedev/mantine; const MyDeleteComponent () { return DeleteButton resourcecategories recordItemId123 /; };确认后将调用deleteOne删除categories资源中 id 为123的记录。类型注释表明默认推断自路由资源名packages/ui-types/src/types/button.tsx#L18-L32。同名的多个资源如果存在多个同名资源例如两个posts使用不同数据提供者可以传入资源的identifier而非name。identifier仅作为资源匹配的主键dataProvider的方法仍会使用Refine/组件中资源定义的name来发起请求。该机制在 documentation/docs/core/refine-component/index.md#L115-L149 有完整说明——比如一个posts走默认dataProvider另一个identifier: featured-posts的posts走typicode数据提供者二者通过identifier区分。在useDeleteButton的实现中mutate时传入的是resource: identifier随后useDelete内部通过select(resourceName)解析回真实资源名packages/core/src/hooks/button/delete-button/index.tsx#L70-L89、packages/core/src/hooks/data/useDelete.ts#L191-L211。onSuccess删除成功后的回调如果你希望在删除请求成功返回后做额外处理比如刷新自定义数据、跳转、埋点使用onSuccessimport { DeleteButton } from refinedev/mantine; const MyDeleteComponent () { return ( DeleteButton recordItemId123 onSuccess{(value) { console.log(value); }} / ); };onSuccess接收的参数类型是DeleteOneResponse即{ data: TData }。在底层它被透传给useDeleteButton并最终挂到mutate(..., { onSuccess: props.onSuccess })上packages/core/src/hooks/button/delete-button/index.tsx#L84-L86。hideText只显示图标当hideText为true时按钮只渲染图标垃圾桶IconTrash不显示文字。这在表格操作列中非常常用import { DeleteButton } from refinedev/mantine; const MyDeleteComponent () { return DeleteButton hideText recordItemId1 /; };从实现看hideText分支渲染的是 Mantine 的ActionIconvariant默认outline颜色red图标为IconTrash size{18} /未隐藏时渲染Button左侧图标同样为IconTrashpackages/mantine/src/components/buttons/delete/index.tsx#L78-L111。类型定义为hideText?: booleanpackages/ui-types/src/types/button.tsx#L11-L16。更多进阶属性来自类型与 hook 定义除文档正文列出的四个属性外DeleteButtonProps还支持以下常用配置packages/ui-types/src/types/button.tsx#L81-L128、packages/core/src/hooks/button/delete-button/index.tsx#L11-L24属性说明默认值mutationMode删除变更的执行模式pessimistic/optimistic/undoable继承Refine/的mutationMode配置invalidates删除成功后需要失效的查询键[list, many]dataProviderName多数据提供者时指定使用哪一个defaultmeta透传给deleteOne的附加元数据如自定义请求头、GraphQL 片段{}accessControl按钮级访问控制{ enabled?: boolean; hideIfUnauthorized?: boolean }{ enabled: true }confirmTitle/confirmOkText/confirmCancelText自定义确认气泡的标题、确认按钮、取消按钮文案分别默认Are you sure?/Delete/Cancel或对应 i18n 键successNotification/errorNotification自定义成功 / 失败通知Refine 内置通知文案onClickMantineButtonProps中原生点击回调—svgIconProps自定义IconTrash图标的IconProps{ size: 18 }hidden/disabled隐藏 / 禁用按钮disabled也能通过权限控制自动注入false这些属性在useDeleteButton中都被接收并参与构建删除请求packages/core/src/hooks/button/delete-button/index.tsx#L48-L59。特别地confirmTitle等三个自定义文案在组件渲染 Popover 时优先级最高confirmTitle ?? defaultConfirmTitle而默认文案来自useTranslate的buttons.confirm/buttons.delete/buttons.cancel键packages/mantine/src/components/buttons/delete/index.tsx#L113-L132、packages/core/src/hooks/button/delete-button/index.tsx#L60-L66。底层原理一条删除请求的完整调用链理解DeleteButton背后发生什么是排查删除问题的关键。整条链路可以概括为DeleteButton 点击确认 └─ useDeleteButton().onConfirm (packages/core/src/hooks/button/delete-button/index.tsx) └─ useDelete().mutate({ id, resource: identifier, mutationMode, ... }) └─ dataProvider(identifier).deleteOne({ resource, id, meta, variables }) └─ 真实 HTTP 请求 (DELETE /resources/:id)① useDeleteButton按钮与数据层的桥梁useDeleteButton返回label、title、hidden、disabled、loading、canAccess、三个确认文案与onConfirmpackages/core/src/hooks/button/delete-button/index.tsx#L26-L37。值得注意的实现细节路由解析通过useResourceParams({ resource: props.resource, id: props.id })从当前路由解析出id、resource、identifier这正是recordItemId与resource默认值来自路由的来源加载态loading id variables?.id isPending——只有当当前按钮对应的记录正在被删除时才显示 loading多行按钮互不干扰无 id 保护onConfirm内部有if (id identifier)守卫id 缺失时静默返回dirty 状态重置删除前调用setWarnWhen(false)避免被未保存更改提示拦截完整参数透传mutationMode、successNotification、errorNotification、meta、dataProviderName、invalidates全部转发给mutate。packages/core/src/hooks/button/delete-button/index.tsx#L39-L89② useDelete基于 TanStack Query 的删除 mutationuseDelete是 TanStack QueryuseMutation的封装packages/core/src/hooks/data/useDelete.ts#L128-L140官方文档将其定位为extended version of TanStack QuerysuseMutationdocumentation/docs/data/hooks/use-delete/index.md。它以dataProvider.deleteOne作为 mutation 函数并叠加了以下能力三种 mutationModepessimistic默认先请求后更新 UI、optimistic先本地更新 UI失败回滚、undoable先弹撤销通知超时后才真正执行默认undoableTimeout为 5000ms。onMutate阶段会在非pessimistic模式下先移除列表/详情缓存中对应记录onError时通过context.previousQueries恢复packages/core/src/hooks/data/useDelete.ts#L253-L327缓存失效onSettled中默认invalidates [list, many]删除完成后自动失效列表与详情查询触发useList/useMany重新拉取packages/core/src/hooks/data/useDelete.ts#L328-L355通知成功后展示Successfully deleted a {resource}失败展示Error (status code: {code})均支持通过successNotification/errorNotification覆盖packages/core/src/hooks/data/useDelete.ts#L390-L409实时与审计成功后会向liveProvider的resources/{resource}频道发布type: deleted事件并调用auditLogProvider的log记录action: deletepackages/core/src/hooks/data/useDelete.ts#L411-L438。官方文档也明确这两项能力分别依赖 Live Provider 与 Audit Log Providerovertime返回overtime.elapsedTime配合overtimeOptions.interval可在请求超时时展示正在处理提示documentation/docs/data/hooks/use-delete/index.md#L89-L113。关于useDelete的完整参数表resource、id、mutationMode、undoableTimeout、onCancel、successNotification、errorNotification、meta、dataProviderName、invalidates与返回值mutation、mutate、mutateAsync、overtime可查阅 documentation/docs/data/hooks/use-delete/index.md 的 API Reference 部分。这些参数绝大多数也以同名 props 暴露在DeleteButton上。③ dataProvider.deleteOne真正发出请求的地方useDelete最终调用数据提供者的deleteOne方法。deleteOne是数据提供者的必需方法签名如下documentation/docs/data/data-provider/index.md#L350-L375deleteOne: async ({ resource, id, variables, meta }) { // 按你的 API 约定发起请求 return { data, }; };参数包括resource资源名通常作为 API 端点路径、id要删除的记录主键、variables可选透传给请求体、meta附加元数据。仓库内置的refinedev/simple-rest提供了一个教科书式实现packages/simple-rest/src/provider.ts#L123-L137deleteOne: async ({ resource, id, variables, meta }) { const url ${apiUrl}/${resource}/${id}; const { headers, method } meta ?? {}; const requestMethod (method as MethodTypesWithBody) ?? delete; const { data } await httpClientrequestMethod; return { data, }; },即默认向GET/POST 的 apiUrl/resource/:id发送DELETE请求并通过meta.headers注入自定义请求头、meta.method覆盖 HTTP 方法例如某些后端要求用POST模拟删除。meta的完整用法自定义请求头、GraphQL 查询生成等参见 documentation/docs/data/hooks/use-delete/index.md#L252-L298。另外如果数据提供者没有实现批量删除deleteManyRefine 会用deleteOne逐条发起请求来兜底。访问控制与权限集成DeleteButton内置了访问控制支持。useDeleteButton内部调用useButtonCanAccess({ action: delete, ... })packages/core/src/hooks/button/delete-button/index.tsx#L52-L58并根据accessControl的配置决定按钮的三种状态默认有权限正常渲染无权限 hideIfUnauthorized: false按钮渲染为禁用态title显示拒绝原因如Access Denied无权限 hideIfUnauthorized: true按钮完全不渲染hidden为 true组件直接返回null。这些行为在共享测试套件中有完整覆盖packages/ui-tests/src/tests/buttons/delete.tsx#L93-L392包括全局 access control 配置、按钮级accessControl{{ enabled: true/false }}覆盖、hideIfUnauthorized的全局/局部组合等场景。测试还验证了显式disabled属性在开启访问控制时依然生效以及禁用enableAccessControl后按钮强制可用。此外Edit/、Show/等基础视图组件的canDelete属性也与DeleteButton联动当canDelete为false时默认的DeleteButton不会渲染deleteButtonProps为undefined你也可以用deleteButtonProps拿到默认属性后自行组合例如在自定义 footer 中渲染DeleteButton {...deleteButtonProps} hideText /documentation/docs/ui-integrations/mantine/components/basic-views/edit/index.md#L1246-L1256。测试保障跨 UI 框架共享的按钮契约DeleteButton的正确性由一套跨 UI 框架共享的测试套件保证。packages/mantine中的测试文件只有寥寥数行packages/mantine/src/components/buttons/delete/index.spec.tsximport { buttonDeleteTests } from refinedev/ui-tests; import { DeleteButton } from ./; describe(Delete Button, () { buttonDeleteTests.bind(this)(DeleteButton); });真正的主体是refinedev/ui-tests中的buttonDeleteTestspackages/ui-tests/src/tests/buttons/delete.tsx它对所有 UI 框架的 DeleteButton 统一断言以下契约默认渲染出Delete文案且按钮可用disabled属性生效且点击不会触发回调hidden属性使按钮不渲染拥有正确的data-testidRefineButtonTestIds.DeleteButtonchildren可以覆盖默认文案hideText只显示图标、不显示文字点击后弹出确认气泡包含Are you sure?与Cancel文案确认后调用deleteOne测试中通过dataProvider注入deleteOneMock验证完整覆盖访问控制的各种组合场景见上一节。这意味着无论使用 Mantine、Ant Design、Material UI 还是 Chakra UIDeleteButton的行为契约是一致的你可以放心地在多框架项目中迁移同样的交互模式。注意事项与最佳实践确认成本即安全成本DeleteButton的确认气泡是防止误删的第一道防线不要在onClick中绕过它直接调用useDelete除非你有明确的二次确认设计。列表页务必传recordItemId列表路由没有:id参数忘记传recordItemId会导致按钮确认后静默无操作onConfirm的if (id identifier)守卫。善用hideText压缩操作列参考 examples/form-mantine-use-form/src/pages/posts/list.tsx 的写法在空间紧张的表格中与ShowButton、EditButton组合使用。软删除需求如果业务要求逻辑删除可借助meta如meta: { soft: true }或自定义dataProvider.deleteOne实现DeleteButton的交互流程无需改动。undoable 模式需要可撤销删除体验时在Refine/全局配置或按钮上设置mutationModeundoable系统会在超时默认 5000ms前展示撤销通知也可用onCancel接管自定义撤销 UIdocumentation/docs/data/hooks/use-delete/index.md#L175-L210。多数据提供者通过dataProviderName指定目标提供者同名资源通过identifier区分documentation/docs/core/refine-component/index.md#L115-L149。深度定制需要彻底改变按钮外观或交互时使用 Refine CLI 的swizzle命令将组件弹出到项目内修改而不是修改node_modules中的包源码。小结DeleteButton是 Refine v5 Mantine 集成中一个小而完整的组件表面上是带确认气泡的按钮底层却串联了资源解析、TanStack Query mutation、三种 mutation mode、缓存失效、实时发布、审计日志与访问控制。理解从DeleteButton→useDeleteButton→useDelete→dataProvider.deleteOne的完整链路能帮助你在遇到删除相关问题时快速定位是按钮层、hook 层还是数据提供者层并在权限、撤销、软删除等复杂需求面前从容地选择正确的扩展点。若需自定义行为官方文档 delete-button/index.md 与 useDelete 文档 是继续深入的起点。【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表