【图文并茂】ant design pro 如何优雅奇妙地让创建和更新页面共用一个 form


如上图所示

一般来说,新建和编辑页面的内容应该是差不多的。
如果分开来写,每个 form 都写一份代码,那就太复杂了。一改的话,可能要改两次
如何共用呢,还要做到,有时候他们有些差异的,比如用户修改的时候可以不用填密码,但是创建时一定要有密码。
创建页面
src/pages/Auth/Roles/components/Create.tsx
import { useIntl } from '@umijs/max';
import { FormInstance, Modal } from 'antd';
import BasicForm from './BasicForm';
import { values } from 'lodash';interface Props {open: boolean;onOpenChange: (visible: boolean) => void;onFinish: (formData: any) => Promise<void>;
}interface Props {form?: FormInstance<any>;newRecord?: boolean;onFinish: (formData: any) => Promise<void>;values?: any;
}const Create: React.FC<Props> = (props) => {const intl = useIntl();const { open, onOpenChange, onFinish } = props;return (<Modaltitle={intl.formatMessage({ id: 'add_new' })}width="45%"open={open}onCancel={() => onOpenChange(false)}destroyOnClose={true}maskClosable={false}footer={null}><BasicForm values={values} newRecord onFinish={onFinish} /></Modal>);
};export default Create;
编辑页面
import { useIntl } from '@umijs/max';
import React from 'react';
import BasicForm from './BasicForm';
import { Modal } from 'antd';export type FormValueType = Partial<API.ItemData>;export type UpdateFormProps = {onCancel: (visible: boolean) => void;onSubmit: (values: FormValueType) => Promise<void>;updateModalOpen: boolean;values: {roles?: { id: number }[];} & Partial<API.ItemData>;
};const UpdateForm: React.FC<UpdateFormProps> = (props) => {const intl = useIntl();const { updateModalOpen, onCancel, onSubmit, values } = props;return (<ModalmaskClosable={false}width="50%"destroyOnClosetitle={intl.formatMessage({ id: 'modify' })}open={updateModalOpen}footer={false}onCancel={() => onCancel(false)}><BasicForm values={values} onFinish={onSubmit} /></Modal>);
};export default UpdateForm;
可以看到它们用的同一个 BasicForm ,只是传参可能有些不同。
index 的引用
{(access.canSuperAdmin || access.canCreateRole) && (<Createopen={createModalOpen}onOpenChange={handleModalOpen}onFinish={async (value) => {const success = await handleAdd(value as API.ItemData);if (success) {handleModalOpen(false);if (actionRef.current) {actionRef.current.reload();}}}}/>)}{(access.canSuperAdmin || access.canUpdateRole) && (<UpdateonSubmit={async (value) => {const success = await handleUpdate(value);if (success) {handleUpdateModalOpen(false);setCurrentRow(undefined);if (actionRef.current) {actionRef.current.reload();}}}}onCancel={handleUpdateModalOpen}updateModalOpen={updateModalOpen}values={currentRow || {}}/>)}
共用的 form
src/pages/Auth/Roles/components/BasicForm.tsx
import { useIntl } from '@umijs/max';
import React, { Key, useState } from 'react';
import { ProForm, ProFormText } from '@ant-design/pro-components';
import { Form, Input, Spin, Tree } from 'antd';
import useQueryList from '@/hooks/useQueryList';
import { FormInstance } from 'antd/es/form';
import { Permission } from '@/apiDataStructures/ApiDataStructure';interface Props {form?: FormInstance<any>;newRecord?: boolean;onFinish: (formData: any) => Promise<void>;values?: any;
}const BasicForm: React.FC<Props> = ({ newRecord, onFinish, values }) => {const intl = useIntl();const { items: permissionGroups, loading } = useQueryList('/permission-groups/list');const [expandedKeys, setExpandedKeys] = useState<Key[]>([]);const [autoExpandParent, setAutoExpandParent] = useState<boolean>(true);const [checkedKeys, setCheckedKeys] = useState<Key[] | { checked: Key[]; halfChecked: Key[] }>(values.permissions?.map((permission: Permission) => `${permission._id}`) ?? [],);const [selectedKeys, setSelectedKeys] = useState<Key[]>([]);const onExpand = (expandedKeysValue: Key[]) => {setExpandedKeys(expandedKeysValue);setAutoExpandParent(false);};const onCheck = (checkedKeysValue: Key[] | { checked: Key[]; halfChecked: Key[] }) => {setCheckedKeys(checkedKeysValue);console.log('checkedKeysValue', checkedKeysValue);};const onSelect = (selectedKeysValue: Key[]) => {setSelectedKeys(selectedKeysValue);};return (<ProForminitialValues={{...values,permissions: values?.permissions?.map((permission: Permission) => permission._id),}}onFinish={async (values) => {await onFinish({...values,permissions: checkedKeys,});}}><ProForm.Group><ProFormTextrules={[{ required: true, message: intl.formatMessage({ id: 'enter_name' }) }]}width="md"label={intl.formatMessage({ id: 'name' })}name="name"/><ProForm.Item name="permissions" label={intl.formatMessage({ id: 'permission_choose' })}><Spin spinning={loading}><TreecheckableonExpand={onExpand}expandedKeys={expandedKeys}autoExpandParent={autoExpandParent}onCheck={onCheck}checkedKeys={checkedKeys}onSelect={onSelect}selectedKeys={selectedKeys}treeData={permissionGroups} // Use filtered top-level groupsfieldNames={{ title: 'name', key: '_id', children: 'children' }}/></Spin></ProForm.Item></ProForm.Group>{!newRecord && (<Form.Item name="_id" label={false}><Input type="hidden" /></Form.Item>)}</ProForm>);
};export default BasicForm;
差异
如果要让创建和编辑页面有不一样的地方
我们只要传不同的值,判断一下即可
比如创建页面
<BasicForm values={values} newRecord onFinish={onFinish} />
更新页面:
<BasicForm values={values} onFinish={onSubmit} />
看到 newRecord 没有,表示是创建页面
然后 basicForm 里
{!newRecord && (<Form.Item name="_id" label={false}><Input type="hidden" /></Form.Item>)}
我的更新页面并不需要传 _id ,所以做了一个判断即可。
或者密码这里:
<ProFormTextrules={[{ required: newRecord, message: intl.formatMessage({ id: 'enter_password' }) }]}width="md"label={intl.formatMessage({ id: 'password' })}name="password"/>
只有新增页面才是 required: newRecord
完结。
- 获取 ant design pro & nodejs & typescript 多角色权限动态菜单管理系统源码*
- 我正在做的程序员赚钱副业 - Shopify 真实案例技术赚钱营销课视频教程
