模态框的两种管理思路

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

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

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

在内部管理状态用到了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部分加就好

相关推荐
爱笑的眼睛112 分钟前
端到端语音识别系统的前沿实践与深度剖析:从RNN-T到Conformer
java·人工智能·python·ai
肠胃炎8 分钟前
Chrome扩展截图功能实现
前端·chrome
郝学胜-神的一滴9 分钟前
Linux系统调用中断机制深度解析
linux·运维·服务器·开发语言·c++·程序人生
老华带你飞10 分钟前
垃圾分类|基于springboot 垃圾分类系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·spring
悟能不能悟13 分钟前
JAVA 中dao层的实体应该属于哪个层次VO,还是DTO,或者其他
java·开发语言
醇氧14 分钟前
在 Spring Service 中使用 private final Gson gson = new Gson(); 是否安全?
java·安全·spring
二狗哈17 分钟前
Cesium快速入门17:与entity和primitive交互
开发语言·前端·javascript·3d·webgl·cesium·地图可视化
chenyuhao202417 分钟前
Linux系统编程:Ext文件系统
linux·运维·服务器·开发语言·网络·c++·后端
xingzhemengyou117 分钟前
python datetime模块使用
前端·python
CodeAmaz19 分钟前
InnoDB的MVCC机制
java·数据库·mvcc