ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Refine 中 useDrawerForm 完整使用指南:在 Drawer 内高效实现创建与编辑表单

Refine 中 useDrawerForm 完整使用指南:在 Drawer 内高效实现创建与编辑表单 Refine 中 useDrawerForm 完整使用指南在 Drawer 内高效实现创建与编辑表单【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refineuseDrawerForm是 Refine 中 antd 集成包提供的高阶表单 Hook它让开发者可以在 Ant DesignDrawer抽屉内直接承载完整的创建create、编辑edit、克隆clone表单流程并自动衔接数据获取、提交、校验与关闭逻辑。本文以documentation/versioned_docs/version-3.xx.xx/api-reference/antd/hooks/form/useDrawerForm.md为骨架结合当前仓库的源码与示例完整讲解其用法、返回值、内部实现与实战细节。读完本文你将能够在自己的 Refine 项目中用最少的样板代码实现列表页点按钮 → 抽屉内填表 → 提交并自动关闭的完整交互。useDrawerForm 是什么useDrawerForm允许你在一个Drawer中管理表单。它返回 Ant DesignForm和Drawer两个组件所需的全部 props把表单状态、抽屉显隐、数据预取编辑时按 id 拉取记录与提交行为全部封装起来。关键在于它是从useForm扩展而来的源码位于 packages/antd/src/hooks/form/useDrawerForm/useDrawerForm.tsimport { useForm, type UseFormProps, type UseFormReturnType } from ../useForm;这意味着useForm的所有能力数据获取、mutation、校验、warnWhenUnsavedChanges等在useDrawerForm中全部可用你只需要额外关心抽屉的打开、关闭与提交后的复位行为。需要注意包名的演进v3 版本文档中使用的是pankod/refine-antd而当前仓库packages/antd/package.json中包名为refinedev/antd版本 6.x已更名为refinedev/antd两者导出的 API 一致。基础用法在抽屉中创建记录先看最典型的创建场景点击列表页的创建按钮打开抽屉填写表单后提交。import React from react; import { List, Create, Table, Form, Select, Input, Drawer, useTable, useDrawerForm, } from refinedev/antd; import { IResourceComponentsProps, HttpError } from refinedev/core; interface IPost { id: number; title: string; status: published | draft | rejected; } const PostList: React.FCIResourceComponentsProps () { const { tableProps } useTableIPost, HttpError(); // 核心声明一个 create 动作的抽屉表单 const { formProps, drawerProps, show, saveButtonProps } useDrawerForm IPost, HttpError, IPost ({ action: create, }); return ( List canCreate createButtonProps{{ onClick: () { show(); // 打开抽屉 }, }} Table {...tableProps} rowKeyid Table.Column dataIndexid titleID / Table.Column dataIndextitle titleTitle / /Table /List {/* 将 drawerProps 展开到 Drawer 上 */} Drawer {...drawerProps} Create saveButtonProps{saveButtonProps} Form {...formProps} layoutvertical Form.Item labelTitle nametitle rules{[{ required: true }]} Input / /Form.Item Form.Item labelStatus namestatus rules{[{ required: true }]} Select options{[ { label: Published, value: published }, { label: Draft, value: draft }, { label: Rejected, value: rejected }, ]} / /Form.Item /Form /Create /Drawer / ); };整个流程中你不需要写任何open/setOpen状态管理也不需要手动处理提交请求drawerProps展开到Drawer后抽屉的open、onClose、width等都由 Hook 托管formProps展开到Form后onFinish已被 Hook 接管提交时会自动调用对应资源的create数据提供器方法saveButtonProps传给Create后保存按钮的 loading、disabled 与点击提交逻辑都已就绪。基础用法在抽屉中编辑记录编辑场景多了一个关键点需要告诉 Hook 编辑哪条记录。通过show(record.id)传入记录 idHook 会自动拉取该记录数据并回填表单。import React from react; import { List, Edit, EditButton, Table, Form, Select, Input, Drawer, useTable, useDrawerForm, Space, } from refinedev/antd; import { IResourceComponentsProps, HttpError } from refinedev/core; const PostList: React.FCIResourceComponentsProps () { const { tableProps } useTableIPost, HttpError(); const { formProps, drawerProps, show, saveButtonProps, id } useDrawerForm IPost, HttpError, IPost ({ action: edit, warnWhenUnsavedChanges: true, // 关闭抽屉时若有未保存修改会弹确认框 }); return ( List canCreate Table {...tableProps} rowKeyid Table.Column dataIndexid titleID / Table.Column dataIndextitle titleTitle / Table.ColumnIPost titleActions dataIndexactions keyactions render{(_, record) ( Space EditButton hideText sizesmall recordItemId{record.id} onClick{() show(record.id)} // 传入 id 打开编辑抽屉 / /Space )} / /Table /List Drawer {...drawerProps} Edit saveButtonProps{saveButtonProps} recordItemId{id} Form {...formProps} layoutvertical {/* 与创建表单相同的字段结构 */} Form.Item labelTitle nametitle rules{[{ required: true }]} Input / /Form.Item Form.Item labelStatus namestatus rules{[{ required: true }]} Select options{[ { label: Published, value: published }, { label: Draft, value: draft }, { label: Rejected, value: rejected }, ]} / /Form.Item /Form /Edit /Drawer / ); };两个容易踩的坑原文档专门用两段 caution 强调了编辑场景的注意点务必记住Refine 不会自动在表格行内添加EditButton。你必须在列表页手动放置EditButton并让它打开编辑抽屉Table.ColumnIPost titleActions dataIndexactions keyactions render{(_value, record) EditButton onClick{() show(record.id)} /} /不要忘记把记录id传给show。无论是edit还是clone动作show都需要 id 才能拉取记录数据并填充表单。源码中handleShow对此有明确校验useDrawerForm.ts当action为edit或clone时只有拿到 id 才会真正打开抽屉。返回值详解useDrawerForm返回的所有值如下表Key说明类型show打开抽屉的函数可传可选id参数(id?: BaseKey) voidformAnt Design 表单实例FormInstanceTVariablesformPropsAnt Design 表单 propsFormPropsdrawerProps托管抽屉的 propsDrawerPropssaveButtonProps提交按钮 props{ disabled: boolean; onClick: () void; loading: boolean; }deleteButtonProps删除按钮 propsDeleteButtonPropssubmit提交方法参数为表单字段值() voidopen抽屉当前是否打开booleanclose关闭抽屉的函数() voidformLoading表单数据加载状态boolean下面逐个说明原文档强调的核心返回值。show打开Drawer的函数。它接收可选的id参数如果提供了id会先获取对应记录数据并用它填充Form。这正是编辑/克隆场景与创建场景的唯一调用差异——创建时调用show()编辑时调用show(record.id)。close关闭Drawer的函数行为与drawerProps.onClose一致。从源码看close实际是handleCloseuseDrawerForm.ts它不只是简单关闭抽屉还会依次处理autoSave成功后按需触发invalidate默认失效[list, many, detail]若warnWhen未保存修改警告开启弹出确认框用户取消则中止关闭关闭抽屉并重置id为undefined。saveButtonProps抽屉内提交按钮所需的全部 propsdisabled、loading等。当saveButtonProps.onClick被调用时会触发form.submit()。源码实现非常直白const saveButtonProps { disabled: formLoading, onClick: () { form.submit(); }, loading: formLoading, };你也可以把这些 props 手动传给自定义按钮。deleteButtonProps抽屉内删除按钮所需的 props。它的onSuccess回调会做两件事把id重置为undefined、把open置为false即删除成功后自动关闭抽屉并清空当前编辑上下文const deleteButtonProps { recordItemId: id, onSuccess: () { setId?.(undefined); close(); }, };formProps管理Form状态与动作所必需的 props底层直接来自useForm。包含管理 AntdForm组件所需的一切如onValuesChange、initialValues、onFieldsChange、onFinish等。注意useDrawerForm会在useForm返回的formProps.onFinish之上再包装一层提交成功后若autoSubmitClose为true则关闭抽屉若autoResetForm为true则调用form.resetFields()复位表单见 useDrawerForm.ts。drawerProps管理Drawer状态与动作的 props包含以下要点width抽屉宽度默认值为500px源码中drawerProps合并时硬编码了该默认值onClose关闭抽屉的函数。当warnWhenUnsavedChanges为true时会先弹出确认框再关闭如果你覆盖了这个函数必须自己处理确认弹窗逻辑open抽屉当前可见状态默认falseforceRender默认true让Drawer立即渲染内容而不是懒渲染这保证了form实例从一开始就存在。drawerProps的最终形态在源码中一目了然drawerProps: { ...drawerProps, width: 500px, onClose: handleClose, open: visible, forceRender: true, },其底层open/onClose状态由useDrawer封装packages/antd/src/hooks/drawer/useDrawer/index.tsx而useDrawer又基于refinedev/core的useModal实现因此抽屉的显隐本质上复用了 Refine 核心的 modal 状态管理。API 参数与配置项PropertiesuseDrawerForm除了useForm的全部 props 外还增加了以下几个专属配置定义见 useDrawerForm.ts参数类型默认值说明actionshow \| edit \| create \| clone—必填声明抽屉表单的动作类型决定数据获取与提交走哪条数据提供器方法defaultVisiblebooleanfalse抽屉初始是否打开useDrawer将drawerProps.open作为useModal的defaultVisibleautoSubmitClosebooleantrue表单提交成功后是否自动关闭抽屉autoResetFormbooleantrue表单提交成功后是否自动重置表单字段syncWithLocationboolean \| { key: string; syncId?: boolean }false是否将抽屉的open/id状态同步到 URL query 参数便于分享/刷新后恢复状态关于action的取值虽然配置类型中声明了四种动作但原文档的两个示例聚焦于create与editclone与show用法类似clone同样需要show(id)传 id。关于全局默认值原文档给出两点重要说明带*的 props 在RefineContext中有默认值也可以在Refine组件上统一配置。useDrawerForm会以Refine传入的值作为默认但局部传入的值会覆盖全局配置。带**的redirect如果未显式配置其默认值取决于action——action为create时默认重定向到edit即刚创建记录的编辑页action为edit时默认重定向到list。Type Parameters类型参数属性说明默认值TData查询结果数据类型需继承BaseRecordBaseRecordTError自定义错误对象需继承HttpErrorHttpErrorTVariables表单字段值类型{}使用示例useDrawerFormIPost, HttpError, IPost({ action: create })其中IPost是自定义记录接口。源码行为验证测试用例怎么说仓库自带的测试文件 packages/antd/src/hooks/form/useDrawerForm/index.spec.tsx 以 300 行用例完整锁定了上述行为是理解 Hook 语义的最快途径初始状态drawerProps.open默认为false传入defaultVisible: true时初始为true关闭行为调用drawerProps.onClose后open变为falseshow 的 id 逻辑action: edit时调用show()无 id抽屉不会打开而show(id)会打开并更新idautoSubmitClose为true时提交成功后抽屉自动关闭为false时提交成功但抽屉保持打开autoResetForm为true时提交成功后表单字段被清空mutationMode 与关闭时机pessimistic模式下抽屉在 mutation 成功后才关闭optimistic/undoable模式下抽屉立即关闭syncWithLocation启用后getOne请求的meta中会包含drawer-posts-edit这类同步 key。这些用例从侧面印证了抽屉的关闭时机、表单复位、id 回填都经过了精心设计且对不同的mutationMode表现一致。进阶一个文件三个抽屉的完整实战示例原文档末尾推荐了完整示例 examples/form-antd-use-drawer-form其核心页面 examples/form-antd-use-drawer-form/src/pages/posts/list.tsx 展示了比基础用法更完整的实战形态创建抽屉useDrawerForm({ action: create, syncWithLocation: true })点击List的createButtonProps.onClick打开编辑抽屉useDrawerForm({ action: edit, syncWithLocation: true })表格行内EditButton通过editDrawerShow(record.id)打开Edit同时接收recordItemId{id}、isLoading{editFormLoading}与deleteButtonProps实现编辑、加载态、删除一体化查看抽屉借助useShow与useState手写第三个只读 Drawer用Show组件展示id、status、title等字段详情。三个抽屉共用一个表格组件createFormProps/editFormProps分别展开到各自的Form互不干扰。同时该示例为Create/Edit设置了contentProps内联样式boxShadow: none、bodyStyle: { padding: 0 }以贴合抽屉场景的视觉需求。总结什么时候用 useDrawerForm如果你的后台管理界面需要在列表页原地完成新增/编辑而不是跳转到独立表单页useDrawerForm就是最贴合的工具它把useForm的数据能力与抽屉的显隐控制无缝粘合默认行为提交即关、提交即复位、500px宽度、强制渲染覆盖了绝大多数 CRUD 场景而action、syncWithLocation、warnWhenUnsavedChanges、autoSubmitClose、autoResetForm等参数则提供了充足的定制空间。结合 form-antd-use-drawer-form 示例 与 useDrawerForm 源码、测试用例 一起阅读你可以快速掌握其全部边界行为并放心在生产环境中使用。【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表