由于开发中常涉及大量弹窗运用,通常情况下,需维护至少两个状态,即:控制显示的open
,与涉及操作的数据源data
。如果在一个页面中,同时有多个弹窗时,则需要维护的状态数据为2n。在此背景下,我们以Ant design
组件库的Modal
和Drawer
组件为例,提供两种状态管理方式以达到对性能的优化,减少组件的渲染。
方式一
根据JS的一些隐式转换规则我们可以优化open
与data
两个状态优化为一个,以Modal
组件示例,具体代码如下:
import { useEffect } from 'react';
import { Modal } from 'antd';
type ModalProps = { data: any; onCancel: () => void; onConfirm: () => void };
export default function CustomModal({ data, onCancel }: ModalProps) {
useEffect(() => {
if (data) {
// 根据传值,进行处理
}
}, [data]);
return (
<Modal title="Modal" open={!!data} onCancel={onCancel}>
// modal content
</Modal>
);
}
// Usage
type ModalData = { id: number; name: string };
export default function Test() {
const [data, setData] = useState<ModalData | false>();
return <CustomModal data={data} onCancel={() => setData(false)} onConfirm={() => {}} />;
}
方式二
在方式一中,如涉及到深层次跨组件传递状态则非常的麻烦,在父组件中维护一个或多个状态需多次逐级传递,当然也可以使用状态管理库来实现相同效果。不过在React中还可以利用useRef
与useImperativeHandle
实现将状态维护在自身中,在某种意义上来说反而是弹窗状态管理的最优解,彻底做到了代码解耦。示例代码如下:
import { useState, useImperativeHandle, forwardRef } from 'react';
import { Modal } from 'antd';
type ModalProps = { fn?: () => void };
type ModalData = { id: number; name: string };
export type CustomModalType = { open?: (v: any) => void } | undefined;
const CustomModal = forwardRef<CustomModalType, ModalProps>(({ fn }, ref) => {
const [data, setData] = useState<ModalData | false>();
useImperativeHandle(ref, () => ({
open: (v) => setData(v),
}));
return (
<Modal title="Modal" open={!!data} onCancel={() => setData(false)}>
// modal content
</Modal>
);
});
// Usage
import { useRef } from 'react';
export default function Test() {
const ref = useRef<CustomModalType>();
return <CustomModal ref={ref} />;
}