如果定义在父级是这样的
father:
const [visible, setVisible] = useState<boolean>(false)
const [modalData, setModalData] = useState<any>()
const onOpen = () => {
// 保存状态,比如需要用
const tmpModalData = {}
setModalData(tmpModalData)
setVisible(true)
}
const onClose = () => {
// todo 清除Modal数据
setVisible(false)
}
<Button onClick={onOpen}>打开modal</Button>
<Modal visible={visible} onOk={onClose} onCancel={onClose} modalData={modalData}>
modal content
</Modal>
优点:符合React数据单向流动的理念。 缺点:当Modal中需要的状态比较多,增加父组件的管理负担。(比如在table中点编辑,往往我们需要获取到当前行的数以及及一些额外的参数,管理起来作为当前modal要使用的值。)
如果在子级中定义Modal的方法,并对外暴露一个open方法,通过open方法拿到当前Modal所需要的数据,使父级与子级解耦。
father:
export interface ModalRefType<T> {
openModal: (values: T) => void;
}
const modalRef = useRef<ModalRefType<DiskIoDetailDrawerParams> | undefined>();
// 在需要打开modal的地方执行该方法
modalRef.current?.openModal({id: 123});
// 把自定义的Modal组件放到父级中,并且绑定ref
<MyDrawer ref={modalRef} title="this is title" />
child:
import { Modal } from '@arco-design/web-react';
import { useBoolean } from 'ahooks';
import { forwardRef, useImperativeHandle } from 'react';
export interface RowDetailModalParams {
id: number;
}
interface Props {
title: string
}
export const RowDetailModal = forwardRef<
ModalRefType<RowDetailModalParams>,
Props
>((props, ref) => {
const [visible, { setTrue, setFalse }] = useBoolean(false);
const {title} = props
const openModal = (values: RowDetailModalParams) => {
const { id } = values;
// todo
setTrue();
};
useImperativeHandle(ref, () => ({
openModal,
}));
return (
<Modal
visible={visible}
onOk={() => {
//todo
setFalse();
}}
onCancel={() => {
// todo
setFalse();
}}
title={title}
>
modal content
</Modal>
);
});
优点:高内聚,子Modal定义了对当前要展示的数据的全部操作,对外保留openModal方法作为入口。且父组件只需要维护handleOpen的方法和一个Ref,增加父组件的代码可维护性。【一大堆useState维护起来真的眼花缭乱】
总结:
在经过把Modal的管理放到父组件,同时有时候一个页面有四五个不同Modal要打开的时候,父组件相当于要维护至少10个state【管理modal的和管理传给Modal数据的state】。 本着“人是死的,数据是活的”的想法,我坚持把Modal的管理定义在Modal内部,对外暴露一个open方法来开启Modal的使用。
如果是你,关于Modal,你的open定义在父级还是子级呢?