模态框的两种管理思路

考试周回到学校反而有时间整理实习期间的随笔

第一种思路是以功能为聚合,例如点击按钮弹出模态框的话那么就写一个按钮组件,这种思路的优点是在一处进行管理功能,用到的时候只需要将按钮嵌入页面就好,但是可能没法在同一处管理某页面用到的所有模态框

第二种思路就是通过钩子函数内部对模态框的状态进行管理,那么外部调用只需要调用方法即可

在内部管理状态用到了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 && (
        <QrcodeDetailModal
          formData={state.qrcodeDetail.data}
          mode={state.qrcodeDetail.mode}
          onClose={closeEditModal}
          onSuccess={() => {
            handleSuccess?.();
            closeEditModal();
          }}
          visible={state.qrcodeDetail.visible}
        />
      )}
      {state.docConfig.visible && (
        <DocConfigModal
          onClose={closeConfigModal}
          onSuccess={() => {
            handleSuccess?.();
          }}
          visible={state.docConfig.visible}
        />
      )}
      {state.qrcodeView.visible && (
        <QrcodeViewModal
          onClose={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 && (
        <QrcodeDetailModal
          formData={state.qrcodeDetail.data}
          mode={state.qrcodeDetail.mode}
          onClose={() => close('qrcodeDetail')}
          onSuccess={() => {
            handleSuccess?.();
            close('qrcodeDetail');
          }}
          visible
        />
      )}
      {state.docConfig.visible && (
        <DocConfigModal
          onClose={() => close('docConfig')}
          onSuccess={handleSuccess}
          visible
        />
      )}
      {state.qrcodeView.visible && (
        <QrcodeViewModal
          onClose={() => close('qrcodeView')}
          qrcodeImgUrl={state.qrcodeView.imgUrl}
          visible
        />
      )}
    </>
  );

  return { modalHandlers, modals };
};

后续如果还想添加页面只需要在ModalState、initialModalState以及钩子内部的modalHandlers中、JSX部分加就好

相关推荐
悦悦子a啊1 分钟前
Maven 项目实战入门之--学生管理系统
java·数据库·oracle
晨光32112 分钟前
Day34 模块与包的导入
java·前端·python
知行合一。。。2 分钟前
Python--01--核心基础
android·java·python
计算机毕设指导67 分钟前
基于微信小程序的水上警务通系统【源码文末联系】
java·spring boot·mysql·微信小程序·小程序·tomcat·maven
陌生的人儿7 分钟前
老年痴呆患者心血管防护,硝酸甘油使用需 “专人监护”
java·eclipse·tomcat·maven·0.3mg硝酸甘油舌下片
BD_Marathon12 分钟前
Vue3_关于CSS样式的导入方式
前端·css
chenyuhao202414 分钟前
Linux系统编程:线程概念与控制
linux·服务器·开发语言·c++·后端
冷雨夜中漫步16 分钟前
Java类加载机制——双亲委派与自定义类加载器
java·开发语言·python
苹果电脑的鑫鑫20 分钟前
vue和react缩进规则的配置项如何配置
前端·vue.js·react.js
BD_Marathon22 分钟前
Vue3_工程文件之间的关系
前端·javascript·vue.js