实现React Modal互斥打开:打开新弹窗时关闭已有弹窗
实现React弹窗打开新窗口自动关闭旧窗口的功能
要实现打开新弹窗时自动关闭已有弹窗的需求,你可以通过Context管理全局弹窗状态的方式来完成,以下是完整的实现步骤:
1. 创建Modal上下文(Context)
首先创建一个Context来存储当前活跃的弹窗标识和控制方法:
import { createContext, useContext } from 'react'; // 创建Modal上下文,初始值为空 const ModalContext = createContext({ currentModalId: null, openModal: () => {}, closeModal: () => {} }); export default ModalContext;
2. 实现Modal Provider组件
这个Provider组件负责管理全局弹窗状态,控制哪个弹窗处于活跃状态:
import { useState } from 'react'; import ModalContext from './ModalContext'; export function ModalProvider({ children }) { // 存储当前活跃的弹窗ID const [currentModalId, setCurrentModalId] = useState(null); // 打开弹窗:设置新的弹窗ID,自动替换旧的 const openModal = (modalId) => { setCurrentModalId(modalId); }; // 关闭弹窗:清空当前弹窗ID const closeModal = () => { setCurrentModalId(null); }; return ( <ModalContext.Provider value={{ currentModalId, openModal, closeModal }}> {children} </ModalContext.Provider> ); }
3. 修改Modal组件
让Modal组件从Context中获取状态,不再依赖外部传入的isOpen和onClose,改为通过弹窗ID来控制显示:
import { useContext } from 'react'; import { createPortal } from 'react-dom'; import ModalContext from './ModalContext'; import Icon from './Icon'; // 假设你的Icon组件路径正确 export function Modal({ id, title, children }) { const { currentModalId, closeModal } = useContext(ModalContext); const isOpen = currentModalId === id; if (!isOpen) return null; return createPortal( <trds-modal class={isOpen ? 'opened' : ''} onClick={closeModal}> <trds-modal_container onClick={e => e.stopPropagation()}> <trds-modal_header> <h2>{title}</h2> <Icon icon="x" onClick={closeModal} /> </trds-modal_header> <trds-modal_body> {children} </trds-modal_body> </trds-modal_container> </trds-modal>, document.body ); }
4. 封装自定义Hook(useModal)
为了方便其他组件调用弹窗控制方法,封装一个自定义Hook:
import { useContext } from 'react'; import ModalContext from './ModalContext'; export function useModal() { const { openModal, closeModal } = useContext(ModalContext); return { openModal, closeModal }; }
5. 使用示例
在你的应用中,先通过ModalProvider包裹根组件,然后在需要使用弹窗的地方调用useModal:
import { ModalProvider } from './ModalProvider'; import { Modal } from './Modal'; import { useModal } from './useModal'; function App() { const { openModal, closeModal } = useModal(); return ( <ModalProvider> <div> <button onClick={() => openModal('modal1')}>打开弹窗1</button> <button onClick={() => openModal('modal2')}>打开弹窗2</button> <Modal id="modal1" title="弹窗1"> <p>这是第一个弹窗的内容</p> <button onClick={closeModal}>关闭弹窗</button> </Modal> <Modal id="modal2" title="弹窗2"> <p>这是第二个弹窗的内容</p> </Modal> </div> </ModalProvider> ); } export default App;
核心逻辑说明
- 每个弹窗通过唯一的
id标识,ModalProvider中只存储当前活跃的弹窗ID - 调用
openModal(newId)时,会直接替换currentModalId,旧弹窗因currentModalId !== id自动隐藏 - 点击弹窗遮罩或关闭按钮时,调用
closeModal清空currentModalId,所有弹窗都会关闭
内容的提问来源于stack exchange,提问作者Daniel Kormos
相关产品推荐
相关产品推荐

