模态框的两种管理思路
考试周回到学校反而有时间整理实习期间的随笔
第一种思路是以功能为聚合,例如点击按钮弹出模态框的话那么就写一个按钮组件,这种思路的优点是在一处进行管理功能,用到的时候只需要将按钮嵌入页面就好,但是可能没法在同一处管理某页面用到的所有模态框
第二种思路就是通过钩子函数内部对模态框的状态进行管理,那么外部调用只需要调用方法即可
在内部管理状态用到了Reducer统一管理多种模态框时的action、state
// 模态框状态类型
interface ModalState {qrcodeDetail: {visible: boolean;mode: 'edit' | 'create';data: QrCodeRecord | null;};docConfig: {visible: boolean;};qrcodeView: {visible: boolean;imgUrl: string;};
}// Action 类型定义
type ModalAction =| { type: 'SHOW_QRCODE_DETAIL'; mode: 'edit' | 'create'; data?: QrCodeRecord }| { type: 'CLOSE_QRCODE_DETAIL' }| { type: 'SHOW_DOC_CONFIG' }| { type: 'CLOSE_DOC_CONFIG' }| { type: 'SHOW_QRCODE_VIEW'; imgUrl: string }| { type: 'CLOSE_QRCODE_VIEW' };// 初始状态
const initialModalState: ModalState = {qrcodeDetail: {visible: false,mode: 'create',data: null,},docConfig: {visible: false,},qrcodeView: {visible: false,imgUrl: '',},
};// Reducer 函数
const modalReducer = (state: ModalState, action: ModalAction): ModalState => {switch (action.type) {case 'SHOW_QRCODE_DETAIL':return {...state,qrcodeDetail: {visible: true,mode: action.mode,data: action.data || null,},};case 'CLOSE_QRCODE_DETAIL':return {...state,qrcodeDetail: {visible: false,mode: 'create',data: null,},};case 'SHOW_DOC_CONFIG':return {...state,docConfig: {visible: true,},};case 'CLOSE_DOC_CONFIG':return {...state,docConfig: {visible: false,},};case 'SHOW_QRCODE_VIEW':return {...state,qrcodeView: {visible: true,imgUrl: action.imgUrl,},};case 'CLOSE_QRCODE_VIEW':return {...state,qrcodeView: {visible: false,imgUrl: '',},};default:return state;}
};// 弹窗管理Hook
export const useModals = (handleSuccess?: () => void) => {const [state, dispatch] = useReducer(modalReducer, initialModalState);const showEditModal = (mode: 'edit' | 'create', record?: QrCodeRecord) => {dispatch({ type: 'SHOW_QRCODE_DETAIL', mode, data: record });};const closeEditModal = () => {dispatch({ type: 'CLOSE_QRCODE_DETAIL' });};const showConfigModal = () => {dispatch({ type: 'SHOW_DOC_CONFIG' });};const closeConfigModal = () => {dispatch({ type: 'CLOSE_DOC_CONFIG' });};const showViewModal = (qrCodeUrl: string) => {dispatch({ type: 'SHOW_QRCODE_VIEW', imgUrl: qrCodeUrl });};const closeViewModal = () => {dispatch({ type: 'CLOSE_QRCODE_VIEW' });};const modalHandlers = {onShowEditModal: showEditModal,onShowViewModal: showViewModal,onShowConfigModal: showConfigModal,};const modals = (<>{state.qrcodeDetail.visible && (<QrcodeDetailModalformData={state.qrcodeDetail.data}mode={state.qrcodeDetail.mode}onClose={closeEditModal}onSuccess={() => {handleSuccess?.();closeEditModal();}}visible={state.qrcodeDetail.visible}/>)}{state.docConfig.visible && (<DocConfigModalonClose={closeConfigModal}onSuccess={() => {handleSuccess?.();}}visible={state.docConfig.visible}/>)}{state.qrcodeView.visible && (<QrcodeViewModalonClose={closeViewModal}qrcodeImgUrl={state.qrcodeView.imgUrl}visible={state.qrcodeView.visible}/>)}</>);return {modalHandlers,modals,};
};
还可以进一步简化,从打开和关闭维度看只有两个action,只不过打开和关闭的是不同的模态框,即不同的ModalState中的Key。
export const useModals = (handleSuccess?: () => void) => {const [state, dispatch] = useReducer(modalReducer, initialModalState);const show = (key: ModalKey, payload?: any) =>dispatch({ type: 'SHOW', key, payload });const close = (key: ModalKey) => dispatch({ type: 'CLOSE', key });const modalHandlers = {onShowEditModal: (mode: 'edit' | 'create', data?: QrCodeRecord) =>show('qrcodeDetail', { mode, data }),onShowConfigModal: () => show('docConfig'),onShowViewModal: (imgUrl: string) => show('qrcodeView', { imgUrl }),};const modals = (<>{state.qrcodeDetail.visible && (<QrcodeDetailModalformData={state.qrcodeDetail.data}mode={state.qrcodeDetail.mode}onClose={() => close('qrcodeDetail')}onSuccess={() => {handleSuccess?.();close('qrcodeDetail');}}visible/>)}{state.docConfig.visible && (<DocConfigModalonClose={() => close('docConfig')}onSuccess={handleSuccess}visible/>)}{state.qrcodeView.visible && (<QrcodeViewModalonClose={() => close('qrcodeView')}qrcodeImgUrl={state.qrcodeView.imgUrl}visible/>)}</>);return { modalHandlers, modals };
};
后续如果还想添加页面只需要在ModalState、initialModalState以及钩子内部的modalHandlers中、JSX部分加就好
