模态框的两种管理思路

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

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

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

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

相关推荐
摇滚侠21 分钟前
SpringMVC 入门到实战 SpringMVC 的执行流程 96
java·后端·spring·maven·intellij-idea
云水一下22 分钟前
Vue.js从零到精通系列(七):高级特性实战——Teleport、异步组件、自定义指令与TypeScript深度结合
前端·vue.js·typescript
唐青枫23 分钟前
Java Liquibase 实战指南:让数据库变更像代码一样可追踪
java
qq43569470124 分钟前
Vue05
前端·vue.js
qq_4221525726 分钟前
PDF 解密工具怎么选?2026 年文档密码移除方案与注意事项
java·前端·pdf
YHHLAI30 分钟前
前端工程化调用 AI 多模态生图模型:Qwen Image Demo 实战
前端·人工智能
布朗克16836 分钟前
38 Spring Boot入门——自动配置、核心注解与Starter机制
java·spring boot·后端
只说证事37 分钟前
2026 国家认可的计算机专业证书
服务器
月巴月巴白勺合鸟月半39 分钟前
在Linux下开发桌面程序
linux·运维·服务器
To_OC43 分钟前
我一直以为 Ajax 是个黑盒,直到我写了这 50 行代码
前端·后端·全栈