ARTICLE DETAIL

资讯详情

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

Refine v5 useModalForm 完全指南:在 Ant Design 弹窗中构建 create / edit / clone 表单

Refine v5 useModalForm 完全指南:在 Ant Design 弹窗中构建 create / edit / clone 表单 Refine v5 useModalForm 完全指南在 Ant Design 弹窗中构建 create / edit / clone 表单【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refineuseModalForm是 Refine v5 中refinedev/antd包提供的高阶表单 Hook用于把 CRUD 表单放进 Ant DesignModal的全部能力并额外返回弹窗的modalProps、开关状态与显隐控制函数让你用最少样板代码实现点击按钮 → 弹出 Modal → 提交表单 → 自动关闭并刷新列表的完整交互闭环。读完本文你将掌握 create / edit / clone 三种模式的标准写法、全部可选参数与返回值并能结合源码理解其内部实现原理。useModalForm 是什么useModalForm允许你在Modal扩展而来因此useForm的所有特性数据获取、提交、mutation mode、redirect 等在useModalForm中均可直接使用。从源码可以确认两者的继承关系在 useModalForm.ts 中useModalForm直接调用了useForm并把useForm返回的结果通过...useFormProps透传出去其返回值类型UseModalFormReturnType是UseFormReturnType剔除saveButtonProps与deleteButtonProps后再叠加弹窗专用字段open、close、show、modalProps等得到的。const { modalProps, formProps, show, close, formLoading, } useModalFormIPost({ action: create, });核心用法非常简单modalProps直接展开到Modal上formProps直接展开到Form上show(id?)负责打开弹窗。Usage三种内置动作模式下面通过create、edit、clone三个示例展示useModalForm的典型用法。三个模式都由action属性驱动配合表格场景中的按钮触发。create新建记录创建模式下点击列表上方的创建按钮即可打开空白表单弹窗。通过List组件的createButtonProps.onClick调用show()来触发弹窗import React from react; import { List, useModalForm, useTable } from refinedev/antd; import { Form, Input, Modal, Select, Table } from antd; const PostList: React.FC () { const { tableProps } useTableIPost(); const { modalProps: createModalProps, formProps: createFormProps, show: createModalShow, } useModalFormIPost({ action: create, }); return ( List // createButtonProps 让我们可以在表格上方创建并管理一个按钮 // 点击按钮时触发 Modal 显示 createButtonProps{{ onClick: () { createModalShow(); }, }} Table {...tableProps} rowKeyid Table.Column dataIndexid titleID / Table.Column dataIndextitle titleTitle / Table.Column dataIndexstatus titleStatus / /Table /List Modal {...createModalProps} Form {...createFormProps} 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 /Modal / ); }; interface IPost { id: number; title: string; status: published | draft | rejected; }edit编辑记录Refine 不会自动为列表中的每行记录添加EditButton /需要你在表格的 Actions 列手动放置。点击EditButton /时通过show(record.id)传入记录 id弹窗中的编辑表单即可据此拉取该条记录的数据。const { modalProps: editModalProps, formProps: editFormProps, show: editModalShow, } useModalFormIPost({ action: edit, warnWhenUnsavedChanges: true, });Table.ColumnIPost titleActions dataIndexactions keyactions render{(_, record) ( Space EditButton hideText sizesmall recordItemId{record.id} onClick{() editModalShow(record.id)} / /Space )} /注意必须把记录的id传给showedit与clone表单都需要依赖该 id 获取记录数据。源码中的handleShow也印证了这一约束——当action为edit或clone时只有传入或已存在id 才会真正打开弹窗见 useModalForm.ts。clone克隆记录克隆模式用于基于已有记录快速创建一条新数据。同样需要手动在列表中加入CloneButton /并传入记录 idconst { modalProps: cloneModalProps, formProps: cloneFormProps, show: cloneModalShow, } useModalFormIPost({ action: clone, });Table.ColumnIPost titleActions dataIndexactions keyactions render{(_, record) ( Space CloneButton hideText sizesmall recordItemId{record.id} onClick{() cloneModalShow(record.id)} / /Space )} /clone 模式会预填原记录的数据提交时走 create 逻辑生成一条全新的记录。Properties配置弹窗表单的开关与默认值useModalForm继承useForm的全部 props详见 use-form 文档的 Properties 小节并额外提供以下弹窗专属配置。所有默认值都能在 useModalForm.ts 的解构赋值中直接找到依据。syncWithLocation当syncWithLocation为true时弹窗的可见状态以及记录的id会与 URL 同步默认值为false。这带来两个实际收益刷新页面后弹窗状态不丢失且弹窗状态可以作为可分享的链接。该属性也可以写成对象形式{ key: string; syncId?: boolean }来定制 URL 查询参数的 key只有当syncId为true时id才会同步到 URLconst modalForm useModalForm({ syncWithLocation: { key: my-modal, syncId: true }, });从源码看未指定key时默认的查询参数名为modal-${identifier}-${action}例如modal-posts-edit内部通过useParsed读取 URL 参数、通过useGo把{ open: true, id }写回 URL见 useModalForm.ts。测试用例should meta[syncWithLocationKey] overrided by default也验证了syncWithLocation: true时getOne请求会携带meta: { modal-posts-edit: undefined }见 index.spec.tsx。defaultFormValues表单的默认值用于预填需要展示的数据useModalForm({ defaultFormValues: { title: Hello World, }, });它也可以传入一个 async 函数来异步获取默认值加载状态通过返回的defaultFormValuesLoading跟踪const { defaultFormValuesLoading } useModalForm({ defaultFormValues: async () { const response await fetch(https://my-api.com/posts/1); const data await response.json(); return data; }, }); 当action为edit或clone时与异步defaultFormValues之间可能产生竞态条件此时表单值将是最后一个完成操作的结果。defaultVisible设为true时弹窗默认显示默认值为falseconst modalForm useModalForm({ defaultVisible: true, });autoSubmitClose提交成功后是否自动关闭弹窗默认值为trueconst modalForm useModalForm({ autoSubmitClose: false, });autoResetForm提交成功后是否重置表单默认值为trueconst modalForm useModalForm({ autoResetForm: false, });autoResetFormWhenClose弹窗关闭时是否重置表单默认值为trueconst modalForm useModalForm({ autoResetFormWhenClose: false, });warnWhenUnsavedChanges设为true后当用户带着未保存的修改离开页面时会弹出警告防止误操作丢失数据默认值为false。也可以在Refine组件中统一配置const modalForm useModalForm({ warnWhenUnsavedChanges: true, });源码中该警告通过window.confirm弹出文案默认是 Are you sure you want to leave? You have unsaved changes.支持通过 i18n 的warnWhenUnsavedChanges键翻译见 useModalForm.ts。overtimeOptions当请求耗时过长时可以通过overtimeOptions显示加载提示。interval是毫秒级的检查间隔onInterval是每个间隔触发的回调。Hook 返回overtime对象elapsedTime为已耗时毫秒数请求完成后变为undefinedconst { overtime } useModalForm({ //... overtimeOptions: { interval: 1000, onInterval(elapsedInterval) { console.log(elapsedInterval); }, }, }); console.log(overtime.elapsedTime); // undefined, 1000, 2000, 3000 4000, ... // 实际使用方式 { elapsedTime 4000 divthis takes a bit longer than expected/div; }autoSave如果希望在用户编辑表单后延时自动保存可以启用autoSave.enabled。默认情况下 autoSave 不会使查询失效但可以通过invalidateOnUnmount与invalidateOnClose在卸载或关闭时让查询失效。它还支持onMutationSuccess与onMutationError回调回调中可用isAutoSave参数判断 mutation 是否由 autoSave 触发。autoSave 只作用于edit模式编辑数据时改动会自动保存而创建新数据时仍需手动提交。enabled启用 autoSave默认falseuseModalForm({ autoSave: { enabled: true, }, });debounce设置 autoSave 的防抖时间毫秒默认1000useModalForm({ autoSave: { enabled: true, debounce: 2000, }, });onFinish在数据发送到服务器之前修改数据useModalForm({ autoSave: { enabled: true, onFinish: (values) { return { foo: bar, ...values, }; }, }, });invalidateOnUnmountHook 卸载时使当前资源关联的list、many、detail查询失效默认false。也可以通过invalidates属性选择要失效的查询类型useModalForm({ autoSave: { enabled: true, invalidateOnUnmount: true, }, });invalidateOnClose弹窗关闭时使当前资源关联的list、many、detail查询失效默认falseuseModalForm({ autoSave: { enabled: true, invalidateOnClose: true, }, });invalidateOnClose的实现位于handleClose中当autoSaveProps.status success时调用invalidate({ id, invalidates, dataProviderName, resource })使缓存失效见 useModalForm.ts。Return ValuesHook 返回什么useModalForm返回useForm的所有返回值外加与Modal协作所需的额外值。formProps管理Form状态与动作所必需的 props底层来自useForm。它包含管理 Ant DesignForm的各类属性onValuesChange、initialValues、onFieldsChange、onFinish等。注意onFinish与formProps.onFinish的区别useModalForm直接返回的onFinish与useForm的onFinish一致而在弹窗场景下提交后关闭弹窗、重置字段是必须的因此formProps.onFinish对onFinish做了扩展在底层额外处理了弹窗关闭与字段清空。如果你需要在提交前定制数据建议使用formProps.onFinish把提交后的收尾工作交给它处理。源码中formProps.onFinish的执行顺序是先await onFinish(values)完成提交再根据autoSubmitClose决定是否close()最后根据autoResetForm决定是否form.resetFields()见 useModalForm.ts。modalPropsModal中统一组装属性说明默认值title弹窗标题基于资源与 action 值自动生成如 Edit test见测试用例 index.spec.tsx由资源名与动作组合okText弹窗内提交按钮的文本SavecancelText弹窗内取消按钮的文本Cancelwidth弹窗宽度1000pxforceRender是否立即渲染弹窗而非懒渲染trueokButtonProps提交按钮所需的所有 propsdisabled、loading等点击okButtonProps.onClick会触发form.submit()基于formLoading派生onOk提交弹窗内Form的函数适合手动提交表单—onCancel关闭弹窗的函数等同于close适合手动关闭—open弹窗当前可见状态boolean默认值取决于defaultVisible。close手动关闭弹窗的函数。内部会依次处理autoSave 失效、warnWhenUnsavedChanges确认、清空id、关闭弹窗、按autoResetFormWhenClose重置字段。配合手动提交的典型写法const { close, modalProps, formProps, onFinish } useModalForm(); const onFinishHandler async (values) { // await onFinish 对未保存更改提示、查询失效、重定向等功能至关重要 // 如果使用 formProps.onFinish它会在内部自动调用 close await onFinish(values); close(); }; return ( Modal {...modalProps} Form {...formProps} onFinish{onFinishHandler} layoutvertical Form.Item labelTitle nametitle Input / /Form.Item /Form /Modal );submit手动提交表单的函数。适合自定义弹窗 footer 按钮的场景const { modalProps, formProps, submit } useModalForm(); return ( Modal {...modalProps} footer{[ Button keysubmit typeprimary onClick{submit} Submit /Button, ]} Form {...formProps} layoutvertical Form.Item labelTitle nametitle Input / /Form.Item /Form /Modal );show打开弹窗的函数可接收可选的记录idconst { modalProps, formProps, show } useModalForm(); return ( Button typeprimary onClick{() show()} Show Modal /Button Modal {...modalProps} Form {...formProps} layoutvertical Form.Item labelTitle nametitle Input / /Form.Item /Form /Modal / );overtimeovertime对象elapsedTime为已耗时毫秒数请求完成后变为undefinedconst { overtime } useModalForm(); console.log(overtime.elapsedTime); // undefined, 1000, 2000, 3000 4000, ...autoSaveProps启用autoSave后Hook 返回包含data、error、status三个属性的 mutation 结果对象status取值包括loading | error | idle | success。defaultFormValuesLoading当defaultFormValues是 async 函数时在该函数 resolve 之前此值为true。FAQ如何在提交前修改表单数据一个常见需求把用户填写的name与surname两个字段合并成fullName再发送给 API。做法是利用formProps.onFinish拦截提交import { Modal, useModalForm } from refinedev/antd; import { Form, Input } from antd; import React from react; export const UserCreate: React.FC () { const { formProps, modalProps } useModalForm({ action: create, }); const handleOnFinish (values) { formProps.onFinish?.({ fullName: ${values.name} ${values.surname}, }); }; return ( Modal {...modalProps} Form {...formProps} onFinish{handleOnFinish} layoutvertical Form.Item labelName namename Input / /Form.Item Form.Item labelSurname namesurname Input / /Form.Item /Form /Modal ); };由于走的是formProps.onFinish提交成功后弹窗关闭、表单重置等收尾逻辑依然由 Hook 自动完成。API ReferenceType Parameters参数说明类型默认值TQueryFnData查询函数返回的结果数据继承BaseRecordBaseRecordBaseRecordTError继承HttpError的自定义错误对象HttpErrorHttpErrorTVariables提交参数的值{}—TDataselect函数返回的结果数据继承BaseRecord未指定时默认取TQueryFnDataBaseRecordTQueryFnDataTResponsemutation 函数返回的结果数据继承BaseRecord未指定时默认取TDataBaseRecordTDataTResponseError继承HttpError的自定义错误对象未指定时默认取TErrorHttpErrorTErrorReturn ValueKey说明类型show打开弹窗的函数(id?: BaseKey) voidformProps管理表单组件所需的 propsFormPropsmodalProps管理弹窗组件所需的 propsModalPropsformLoading表单加载状态booleansubmit提交方法参数为表单字段值() voidopen弹窗是否打开booleanclose关闭弹窗的函数() voiddefaultFormValuesLoading默认表单值的加载状态booleanformAnt Design 表单实例FormInstanceTVariablesidedit 动作对应的记录 idBaseKey \| undefinedsetIdid的 setterDispatchSetStateActionBaseKey \| undefinedquery记录查询的结果QueryObserverResult{ data: TData }mutation提交表单触发的 mutation 结果UseMutationResult{ data: TData }, TError, { resource: string; values: TVariables; }, unknownovertime超时加载 props{ elapsedTime?: number }autoSaveProps自动保存 props{ data: UpdateResponseTData \| undefined, error: HttpError \| null, status: loading \| error \| idle \| success }结合源码理解内部行为默认值定义defaultVisible false、autoSubmitClose true、autoResetForm true、autoResetFormWhenClose true全部在 useModalForm.ts 的入口解构中声明与文档描述完全一致。mutationMode 与关闭时机测试用例验证了不同 mutation mode 下弹窗的关闭行为——pessimistic模式会等待 mutation 成功后才关闭弹窗而optimistic/undoable模式提交后立即关闭见 index.spec.tsx。formProps.onFinish中await onFinish(values)正是保证该时序的关键。基础弹窗状态管理useModalForm底层复用了refinedev/antd的useModal见 useModal/index.tsx它把核心useModal的visible映射为 Ant Design Modal 的open并接管onCancel默认关闭行为useModalForm再在其上叠加handleShow/handleClose完成 id 注入、未保存警告、自动重置等增强逻辑。真实可运行示例仓库中的 form-antd-use-modal-form 示例同时演示了 create 与 edit 两个弹窗、syncWithLocation以及独立的 Show 弹窗完整代码见 examples/form-antd-use-modal-form/src/pages/posts/list.tsx。可通过以下命令在本地运行npm create refine-applatest -- --example form-antd-use-modal-form小结useModalForm把 Refine 的表单数据流与 Ant Design 的 Modal 弹窗无缝衔接action: create | edit | clone决定表单行为syncWithLocation让弹窗状态可被 URL 记忆autoSave为编辑场景提供防抖自动保存autoSubmitClose/autoResetForm/autoResetFormWhenClose三个开关精确控制提交与关闭后的收尾动作。配合源码中明确的默认值与测试用例你可以放心地把它当作弹窗 CRUD 的标准方案。【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表