自己封装的抽屉组件,使用时却翻车了

305 阅读3分钟

如图所示,封装了一个侧边抽屉组件,所有的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}
/>

问题:回显出现问题,每次点击修改,只有第一次是正常回显的,第二次点击修改回显失败!

image.png 第一次: image.png 第二次: image.png

命名代码里写了回显的逻辑,为什么第二次就没了? 抓耳挠腮十分钟......百思不得其解。 上个厕所,洗把脸,冷静一下,突然想到:当我关闭抽屉的时候做了什么? 根据代码逻辑,做了两件事: 1.关闭弹窗 2.重置表单 问题应该出在这两步上了,终于在使用的地方发现端倪!

image.png

我直接使用了二次封装的组件,二次封装时,使用了useEffect进行回显,依赖项为空,仅在组件初次加载时执行,那我这里的关闭,组件销毁了吗?当然没有!只是隐藏了而已,所以useEffect从始至终只执行了一次,我每次关闭都把弹窗表单置空了,所以第二次回显必然为空! 修改一下代码:

image.png

借助isOpen变量将组件完全销毁,就可以使useEffect多次执行! 改完后恢复正常了,每次都可以回显。

image.png

看来二次封装并不是一件容易得事情。