跳到正文
当下的七炎
返回

如何在 React 中管理弹窗状态:三种方法的示例

编辑文章

如何在 React 中管理弹窗状态:三种方法的示例

在 React 中管理弹窗的状态有多种方法。本文将介绍三种常用的方法,并通过简单的示例代码进行演示。这三种方法分别是:

  1. 使用存储 State 更新函数的引用
  2. 使用 Context API
  3. 使用 React.forwardRef 和 useImperativeHandle

方法一:使用存储 State 更新函数的引用

这种方法通过在全局存储 State 更新函数的引用来控制弹窗的显示和隐藏。下面是一个简单的示例:

import React, { useState, useEffect } from 'react';
import { Modal, Button } from 'antd';

// 定义一个对象来存储弹窗状态
interface ModalState {
  visible: boolean;
  applyId: number | null;
  ruleId: number | null;
}

// 全局引用存储 State 更新函数
let setModalStateRef: React.Dispatch<React.SetStateAction<ModalState>> | null = null;

export function toggleModal(visible: boolean, applyId?: number, ruleId?: number) {
  if (setModalStateRef) {
    setModalStateRef((prev) => ({
      ...prev,
      visible,
      applyId: visible ? applyId ?? null : null,
      ruleId: visible ? ruleId ?? null : null,
    }));
  }
}

const ModalComponent: React.FC = () => {
  const [modalState, setModalState] = useState<ModalState>({
    visible: false,
    applyId: null,
    ruleId: null,
  });

  useEffect(() => {
    setModalStateRef = setModalState;
    return () => {
      setModalStateRef = null;
    };
  }, []);

  const handleCancel = () => {
    setModalState((prev) => ({
      ...prev,
      visible: false,
      applyId: null,
      ruleId: null,
    }));
  };

  return (
    <Modal visible={modalState.visible} onCancel={handleCancel}>
      <p>申请ID: {modalState.applyId}</p>
      <p>规则ID: {modalState.ruleId}</p>
    </Modal>
  );
};

const App: React.FC = () => {
  return (
    <div>
      <Button onClick={() => toggleModal(true, 123, 456)}>显示弹窗</Button>
      <Button onClick={() => toggleModal(false)}>隐藏弹窗</Button>
      <ModalComponent />
    </div>
  );
};

export default App;

方法二:使用 Context API

Context API 适用于在整个组件树中共享状态。下面是一个简单的示例:

import React, { createContext, useContext, useState, ReactNode } from 'react';
import { Modal, Button } from 'antd';

interface ModalState {
  visible: boolean;
  applyId: number | null;
  ruleId: number | null;
}

interface ModalContextType {
  modalState: ModalState;
  setModalState: React.Dispatch<React.SetStateAction<ModalState>>;
}

const ModalContext = createContext<ModalContextType | undefined>(undefined);

const ModalProvider = ({ children }: { children: ReactNode }) => {
  const [modalState, setModalState] = useState<ModalState>({
    visible: false,
    applyId: null,
    ruleId: null,
  });

  return (
    <ModalContext.Provider value={{ modalState, setModalState }}>
      {children}
    </ModalContext.Provider>
  );
};

const useModal = () => {
  const context = useContext(ModalContext);
  if (!context) {
    throw new Error('useModal must be used within a ModalProvider');
  }
  return context;
};

const ModalComponent: React.FC = () => {
  const { modalState, setModalState } = useModal();

  const handleCancel = () => {
    setModalState({
      visible: false,
      applyId: null,
      ruleId: null,
    });
  };

  return (
    <Modal visible={modalState.visible} onCancel={handleCancel}>
      <p>申请ID: {modalState.applyId}</p>
      <p>规则ID: {modalState.ruleId}</p>
    </Modal>
  );
};

const App: React.FC = () => {
  const { setModalState } = useModal();

  const showModal = () => {
    setModalState({
      visible: true,
      applyId: 123,
      ruleId: 456,
    });
  };

  const hideModal = () => {
    setModalState({
      visible: false,
      applyId: null,
      ruleId: null,
    });
  };

  return (
    <div>
      <Button onClick={showModal}>显示弹窗</Button>
      <Button onClick={hideModal}>隐藏弹窗</Button>
      <ModalComponent />
    </div>
  );
};

const AppWrapper: React.FC = () => {
  return (
    <ModalProvider>
      <App />
    </ModalProvider>
  );
};

export default AppWrapper;

方法三:使用 React.forwardRef 和 useImperativeHandle

这种方法通过 ref 将子组件的方法暴露给父组件。下面是一个简单的示例:

import React, { useState, useImperativeHandle, forwardRef, useRef } from 'react';
import { Modal, Button } from 'antd';

interface ModalState {
  visible: boolean;
  applyId: number | null;
  ruleId: number | null;
}

interface ModalHandle {
  toggleModal: (visible: boolean, applyId?: number, ruleId?: number) => void;
}

const ModalComponent = forwardRef<ModalHandle>((_, ref) => {
  const [modalState, setModalState] = useState<ModalState>({
    visible: false,
    applyId: null,
    ruleId: null,
  });

  useImperativeHandle(ref, () => ({
    toggleModal(visible, applyId, ruleId) {
      setModalState({
        visible,
        applyId: visible ? applyId ?? null : null,
        ruleId: visible ? ruleId ?? null : null,
      });
    },
  }));

  const handleCancel = () => {
    setModalState({
      visible: false,
      applyId: null,
      ruleId: null,
    });
  };

  return (
    <Modal visible={modalState.visible} onCancel={handleCancel}>
      <p>申请ID: {modalState.applyId}</p>
      <p>规则ID: {modalState.ruleId}</p>
    </Modal>
  );
});

const App: React.FC = () => {
  const modalRef = useRef<ModalHandle>(null);

  const showModal = () => {
    modalRef.current?.toggleModal(true, 123, 456);
  };

  const hideModal = () => {
    modalRef.current?.toggleModal(false);
  };

  return (
    <div>
      <Button onClick={showModal}>显示弹窗</Button>
      <Button onClick={hideModal}>隐藏弹窗</Button>
      <ModalComponent ref={modalRef} />
    </div>
  );
};

export default App;

结论

这三种方法各有优劣:

选择哪种方法取决于具体的需求和项目架构。希望本文的示例代码能帮助您更好地理解和选择适合的方法来管理 React 中的弹窗状态。


编辑文章
分享这篇文章:

评论

使用 GitHub 账号登录后即可评论


上一篇
React 中模块作用域变量的可访问性分析
下一篇
git stash的基本用法