如图所示,封装了一个侧边抽屉组件,所有的DOM结构通过children属性传入,使用form实例进行表单的管理, 封装的组件代码如下:
import { DrawerForm } from '@ant-design/pro-components';
import { CloseOutlined } from '@ant-design/icons';
import React from 'react';
// 封装的 公共抽屉组件
/**
*
* @param {*} children
* @param {*} footerButtons 保存关闭按钮
* @param {*} triggerDom 触发抽屉的dom
* @param {*} title 标题
* @param {*} openFlag 抽屉是否打开
* @param {*} setOpenFlag 打开关闭抽屉的方法
* @param {*} handleSubmit 提交表单的方法
* @param {*} form 父组件传递过来的form实例
* @returns
*/
export default function CommonDrawer({ children, footerButtons, triggerDom = null, title, openFlag = false, setOpenFlag, handleSubmit, form, width = 950, labelCol = 10, wrapperCol = 14 }) {
return (
<DrawerForm
form={form}
submitter={{
resetButtonProps: { type: 'dashed' },
submitButtonProps: { style: { display: 'none' } },
resetButtonRender: (_, dom) => null,
render: (props, defaultDoms) => {
return footerButtons;
},
}}
layout="horizontal" // 表单布局
labelCol={{ span: labelCol }} // 标签宽度
wrapperCol={{ span: wrapperCol }} // 控件宽度
drawerProps={{
closeIcon: null,
destroyOnClose: true,
extra: (
<CloseOutlined
onClick={() => {
setOpenFlag(false);
}}
/>
),
}}
width={width}
visible={openFlag}
onVisibleChange={(e) => {
setOpenFlag(e);
}}
onFinish={() => handleSubmit}
title={
<span
style={{
color: '#1F1F1F',
fontSize: '18px',
fontWeight: 600,
height: '22px',
lineHeight: '22px',
}}
>
{title}
</span>
}
trigger={triggerDom}
>
{children}
</DrawerForm>
);
}
使用组件代码如下(进行了二次封装):
import CommonDrawer from '@/components/CommonDrawer';
import DrawerBox from '@/components/DrawerBox';
import OssUploader from '@/components/MallManagement/PriceAndInventory/ImageUploader';
import { addOrReverseGroupBuyItem } from '@/services/groupBy';
import { getImagePathAll, getImageSrc, ternaryOperator } from '@/utils/newUtils';
import { Button, Col, DatePicker, Form, Input, InputNumber, Row } from 'antd';
import moment from 'moment';
import React, { useEffect, useState } from 'react';
export default function({ title, operationType = 'view', refresh, record, openFlag, setDrawerMessage }) {
const [form] = Form.useForm();
const [startTime, setStartTime] = useState(null);
// 表单数据回显
useEffect(() => {
form.setFieldsValue({ ...record, date: [moment(record.startTime), moment(record.endTime)], mainImage: getImagePathAll(record.mainImage) });
}, []);
const setOpenFlag = (e) => {
setDrawerMessage((pre) => ({ ...pre, isOpen: e }));
};
// 保存
const handleSubmit = () => {
form.validateFields()
.then((values) => {
const { date, mainImage } = values;
const params = {
...values,
startTime: `${moment(date[0]).format('YYYY-MM-DD HH:mm')}:00`,
endTime: `${moment(date[1]).format('YYYY-MM-DD HH:mm')}:00`,
mainImage: getImageSrc(mainImage?.[0])[0].url,
};
delete params.date;
addOrReverseGroupBuyItem(params).then((res) => {
if (res?.code === 200) {
form.resetFields();
setDrawerMessage((pre) => ({ ...pre, isOpen: false }));
refresh();
}
});
})
.catch((errorInfo) => {
console.log('表单验证失败:', errorInfo);
});
};
return (
<div>
<CommonDrawer
openFlag={openFlag}
width={1100}
setOpenFlag={setOpenFlag}
footerButtons={ternaryOperator(
operationType === 'view',
[
<Button
key={'cancel'}
onClick={() => {
form.resetFields();
setOpenFlag(false);
}}
>
取消
</Button>,
],
[
<Button
key={'cancel'}
onClick={() => {
form.resetFields();
setOpenFlag(false);
}}
>
取消
</Button>,
<Button type="primary" key={'save'} onClick={handleSubmit}>
保存
</Button>,
],
)}
colon={false}
form={form}
title={title}
labelCol={8}
wrapperCol={16}
>
<DrawerBox title="基础信息">
<Row justify={'space-between'}>
<Col span={12}>
<Form.Item label="团购名称" name="name" rules={[{ required: true }]} colon={false}>
<Input placeholder="请输入团购名称" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="购买人数" name="purchaseCount" rules={[{ required: true }]} colon={false}>
<InputNumber placeholder="请输入购买人数" min={0} style={{ width: '100%' }} />
</Form.Item>
</Col>
</Row>
<Row justify={'space-between'}>
<Col span={12}>
<Form.Item label="团购链接" name="link" rules={[{ required: true }]} colon={false}>
<Input placeholder="请输入团购链接" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="排序" name="sort" rules={[{ required: true }]} colon={false}>
<InputNumber placeholder="请输入排序" min={0} style={{ width: '100%' }} />
</Form.Item>
</Col>
</Row>
<Row justify={'space-between'}>
<Col span={12}>
<Form.Item label="团购时间" name="date" rules={[{ required: true }]} colon={false}>
<DatePicker.RangePicker
format="YYYY-MM-DD HH:mm"
showTime={{ format: 'HH:mm' }}
placeholder={['请选择开始时间', '请选择结束时间']}
style={{ width: '100%' }}
onCalendarChange={(dates) => setStartTime(dates?.[0])}
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="主图" name="mainImage" rules={[{ required: true }]} colon={false}>
<OssUploader
value={form.getFieldValue('mainImage')}
isCropEnableds={false}
maxSize={1}
onChange={(url) => {
form.setFieldValue('mainImage', url);
}}
target={12}
/>
</Form.Item>
</Col>
</Row>
</DrawerBox>
</CommonDrawer>
</div>
);
}
最终引入使用:
<GroupBuyMessage
openFlag={drawerMessage.isOpen}
operationType={drawerMessage.operationType}
setDrawerMessage={setDrawerMessage}
record={drawerMessage.record}
title={drawerMessage.title}
refresh={handleRefresh}
/>
问题:回显出现问题,每次点击修改,只有第一次是正常回显的,第二次点击修改回显失败!
第一次:
第二次:
命名代码里写了回显的逻辑,为什么第二次就没了? 抓耳挠腮十分钟......百思不得其解。 上个厕所,洗把脸,冷静一下,突然想到:当我关闭抽屉的时候做了什么? 根据代码逻辑,做了两件事: 1.关闭弹窗 2.重置表单 问题应该出在这两步上了,终于在使用的地方发现端倪!
我直接使用了二次封装的组件,二次封装时,使用了useEffect进行回显,依赖项为空,仅在组件初次加载时执行,那我这里的关闭,组件销毁了吗?当然没有!只是隐藏了而已,所以useEffect从始至终只执行了一次,我每次关闭都把弹窗表单置空了,所以第二次回显必然为空! 修改一下代码:
借助isOpen变量将组件完全销毁,就可以使useEffect多次执行! 改完后恢复正常了,每次都可以回显。
看来二次封装并不是一件容易得事情。