模态框的两种管理思路

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

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

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

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

相关推荐
m0_748248022 小时前
C++ 异常处理全解析:从语法到设计哲学
java·c++·word
仟濹2 小时前
IDEA 软件下载 + 安装 | 操作步骤
java·ide·intellij-idea
毕设源码-赖学姐2 小时前
【开题答辩全过程】以 法院信访投诉平台为例,包含答辩的问题和答案
java·eclipse
snow@li2 小时前
前端:前端/浏览器 可以录屏吗 / 实践 / 录制 Microsoft Edge 标签页、应用窗口、整个屏幕
前端·浏览器录屏·前端录屏·web录屏
依_旧2 小时前
MySQL下载安装配置(超级超级入门级)
java·后端
李贺梖梖2 小时前
CSS学习
前端·css
vvw&2 小时前
如何在 Ubuntu 上安装 PostgreSQL
linux·运维·服务器·数据库·ubuntu·postgresql
蚂小蚁2 小时前
一文吃透:宏任务、微任务、事件循环、浏览器渲染、Vue 批处理与 Node 差异(含性能优化)
前端·面试·架构