Refine v5 Mantine 教程:SaveButton 组件——表单保存动作的完整实现与定制指南
2026/9/13 5:13:25 网站建设 项目流程

Refine v5 Mantine 教程:SaveButton 组件——表单保存动作的完整实现与定制指南

【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine

<SaveButton>是 Refine v5 中专门用于表单保存动作的按钮组件,基于 Mantine<Button>构建,是 Edit / Create 页面表单提交流程的核心交互元素。本文以 documentation/docs/ui-integrations/mantine/components/buttons/save-button/index.md 为主体,深入讲解其用法、hideText属性,并结合仓库源码剖析其底层实现与测试验证。

SaveButton 是什么

<SaveButton>@refinedev/mantine包导出的按钮组件,它在 Mantine<Button>返回的saveButtonProps会为按钮附加提交、校验、加载态等行为。

从源码实现看,SaveButton 组件 的核心逻辑非常简洁:

// packages/mantine/src/components/buttons/save/index.tsx export const SaveButton: React.FC<SaveButtonProps> = ({ hideText = false, svgIconProps, children, ...rest }) => { const { label } = useSaveButton(); const { variant, styles, ...commonProps } = rest; return hideText ? ( <ActionIcon ...> <IconDeviceFloppy size={18} {...svgIconProps} /> </ActionIcon> ) : ( <Button variant="filled" leftIcon={<IconDeviceFloppy size={18} {...svgIconProps} />} ...> {children ?? label} </Button> ); };

几个值得注意的设计点:

  • 默认渲染为 Mantine<Button>,使用filled变体,左侧自带一个软盘图标(IconDeviceFloppy);
  • 按钮文字优先取children,未传时回退到useSaveButton()返回的label
  • label并非硬编码字符串,而是通过useActionableButtonHook 从 i18n 翻译函数获取,key 为buttons.save,fallback 为humanize("save"),即 "Save",详见 actionable-button/index.tsx 与 hooks/button/index.tsx。

这意味着 SaveButton 天然支持多语言环境:只要在 i18n Provider 中配置buttons.save的翻译,按钮文字就会自动本地化。

在 Edit 页面中使用 SaveButton

SaveButton 最常见的用法是与useForm配合,出现在编辑页面的表单提交场景。原文档给出了完整示例,核心思路是把useForm返回的saveButtonProps透传给<Edit>组件的同名属性,由Edit内部的页脚自动渲染 SaveButton:

import { Edit, useForm, useSelect } from "@refinedev/mantine"; import { Select, TextInput } from "@mantine/core"; const PostEdit: React.FC = () => { const { saveButtonProps, getInputProps, refineCore: { query }, } = useForm<IPost>({ initialValues: { title: "", status: "", category: { id: "", }, }, validate: { title: (value) => (value.length < 2 ? "Too short title" : null), status: (value) => (value.length <= 0 ? "Status is required" : null), category: { id: (value) => (value.length <= 0 ? "Category is required" : null), }, }, }); const postData = query?.data?.data; const { selectProps } = useSelect<ICategory>({ resource: "categories", defaultValue: postData?.category.id, }); return ( <Edit saveButtonProps={saveButtonProps}> <form> <TextInput mt={8} label="Title" placeholder="Title" {...getInputProps("title")} /> <Select mt={8} label="Status" placeholder="Pick one" {...getInputProps("status")} data={[ { label: "Published", value: "published" }, { label: "Draft", value: "draft" }, { label: "Rejected", value: "rejected" }, ]} /> <Select mt={8} label="Category" placeholder="Pick one" {...getInputProps("category.id")} {...selectProps} /> </form> </Edit> ); }; interface ICategory { id: number; title: string; } interface IPost { id: number; title: string; status: "published" | "draft" | "rejected"; category: { id: number }; }

saveButtonProps 里到底装了什么

saveButtonProps之所以能把"保存"动作接到表单上,是因为 Edit 组件 在内部对传入的 props 做了加工:

// packages/mantine/src/components/crud/edit/index.tsx const saveButtonProps: SaveButtonProps = { ...(isLoading ? { disabled: true } : {}), ...saveButtonPropsFromProps, };

然后将其渲染在默认页脚按钮区域:

const defaultFooterButtons = ( <> {isDeleteButtonVisible && <DeleteButton {...deleteButtonProps} />} <SaveButton {...saveButtonProps} /> </> );

也就是说,在isLoadingtrue(例如查询数据或提交中)时,保存按钮会自动进入disabled状态,避免用户重复提交。Create 页面 create/index.tsx 采用了完全相同的模式。这一点对表单交互体验至关重要,也是saveButtonProps相比手动编写<button type="submit">的核心价值所在。

属性详解:hideText

hideText用于控制按钮文字是否显示。当设为true时,按钮只保留图标(软盘),适合工具栏、紧凑布局或已附带文字说明的场景:

import { SaveButton } from "@refinedev/mantine"; const MySaveComponent = () => { return <SaveButton hideText />; };

从源码可以看到hideText的完整渲染逻辑(save/index.tsx):

  • hideTexttrue:渲染为 Mantine<ActionIcon>(图标按钮),默认variant="filled"color="primary";如果调用方传了variant,则通过mapButtonVariantToActionIconVariant做一次映射(definitions/button/index.ts),该映射仅将white变体转换为default,其余原样透传;
  • hideTextfalse(默认)时:渲染为常规<Button>,文字为children ?? label

两种形态都会带上data-testidRefineButtonTestIds.SaveButton)与classNameRefineButtonClassNames.SaveButton),便于测试与全局样式定制。

API 一览

SaveButton的 Props 类型定义在 ui-types/src/types/button.tsx:

export type RefineSaveButtonProps< TComponentProps extends {} = Record<string, unknown>, TExtraProps extends {} = {}, > = RefineButtonCommonProps & RefineButtonLinkingProps & TComponentProps & TExtraProps & {};

展开后,常用属性包括:

属性类型说明
hideTextboolean是否隐藏文字只显示图标,默认false
childrenReactNode自定义按钮文字,未传时使用默认 label("Save")
onClickPointerEventHandler点击回调,来自RefineButtonLinkingProps
variantButtonVariantMantine 按钮变体,透传给底层 Button
svgIconPropsIconProps透传给软盘图标的属性(Mantine 包特有扩展)

在 mantine 包的类型定义 中,SaveButtonProps还额外组合了svgIconProps这类 Mantine 特有的扩展属性,用于定制图标尺寸、颜色等。由于TComponentProps默认继承 Mantine<Button>的全部ButtonPropssizecolorradiusloading等原生属性均可直接透传。

用 Refine CLI swizzle 定制

原文档特别提到:可以用Refine CLI对组件执行 swizzle 操作,将其"弹出"到你的项目源码中,再进行深度定制。swizzle 后组件会成为项目内的普通组件,你可以直接修改其 JSX、样式或逻辑,而不受包更新影响。相关 CLI 说明见 packages/cli 的文档与实现。

源码验证:测试覆盖了什么

@refinedev/ui-tests提供了一套跨 UI 库通用的 SaveButton 测试,Mantine 实现通过一行代码接入(save/index.spec.tsx):

import { buttonSaveTests } from "@refinedev/ui-tests"; import { SaveButton } from "./"; describe("Save Button", () => { buttonSaveTests.bind(this)(SaveButton); });

通用测试用例定义在 ui-tests/src/tests/buttons/save.tsx,覆盖了五个核心行为:

  1. 基本渲染<SaveButton />能正常挂载;
  2. test-id:渲染结果中存在RefineButtonTestIds.SaveButton
  3. children 渲染:传入<SaveButton>refine</SaveButton>时,页面文本中出现 "refine";
  4. hideText<SaveButton hideText />时,页面文本中不再出现 "Save"(只显示图标);
  5. 点击回调:点击按钮触发onClick且只触发一次。

同时,useActionableButton本身也有单测(actionable-button/index.spec.tsx),验证了save/export/import三种类型分别返回 "Save" / "Export" / "Import" 的默认标签。这些测试保证了 SaveButton 在四个主流 UI 库(Ant Design、MUI、Mantine、Chakra UI)之间的行为一致性。

小结

在 Refine v5 中,SaveButton 是一个"薄封装 + 深度集成"的组件:

  • 呈现层由 Mantine<Button>承载,支持hideText纯图标模式与svgIconProps图标定制;
  • 行为层useFormsaveButtonProps注入,通过 Edit / Create 页脚自动获得提交、校验、加载态禁用等能力;
  • 文案层useActionableButton提供,默认 "Save",可经由buttons.save翻译 key 实现 i18n 本地化;
  • 可定制性由 Refine CLI swizzle 保障,弹出源码后可按需改造。

掌握 SaveButton 的用法与内部机制,是构建专业、可维护的 Mantine 后台表单界面的基础一步。

【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询