如何点击react-router-dom的Link组件关闭Bootstrap模态窗口?
这个场景我太熟了!Bootstrap原生模态框和react-router的Link配合时,确实会遇到点小麻烦——点击Link后路由跳了,但模态框还留在页面上。给你几个实用的解决方案,按需选就行:
方案1:监听路由变化,自动关闭模态框(最省心)
如果希望只要路由发生变化,不管是点击Link还是其他方式跳转,模态框都自动关闭,这个方案最通用,不用修改Link的使用方式。
先修改你的ModalWrapper组件,加入路由监听逻辑:
import { useEffect, useRef } from 'react'; import { useLocation } from 'react-router-dom'; export const ModalWrapper = (props) => { const { children, title, modalName } = props; const modalRef = useRef(null); const location = useLocation(); // 路由变化时关闭模态框 useEffect(() => { const modalElement = modalRef.current; if (modalElement) { // 获取Bootstrap模态框实例 const bootstrapModal = window.bootstrap.Modal.getInstance(modalElement); // 只有当模态框处于显示状态时才关闭 if (bootstrapModal && bootstrapModal._isShown) { bootstrapModal.hide(); } } }, [location]); return ( <div ref={modalRef} className="modal fade" id={`modal-${modalName}`} tabIndex="-1" role="dialog" aria-labelledby="modal-label" aria-hidden="true" > <div className="modal-dialog modal"> <div className="modal-content" style={{ overflow: 'hidden' }}> <div className="modal-header"> {title} <button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div className="modal-body"> {children} {/* 直接用原生Link即可,路由变化时模态框自动关闭 */} <Link to="/target-page">点击跳转并关闭模态框</Link> </div> </div> </div> </div> ); };
方案2:自定义点击逻辑,先关模态框再导航
如果只想在特定Link点击时关闭模态框,可以自定义点击事件,先关闭模态框再执行导航:
第一步:修改ModalWrapper支持ref传递
import { forwardRef } from 'react'; // 用forwardRef把外部ref传递给模态框根元素 export const ModalWrapper = forwardRef((props, ref) => { const { children, title, modalName } = props; return ( <div ref={ref} className="modal fade" id={`modal-${modalName}`} tabIndex="-1" role="dialog" aria-labelledby="modal-label" aria-hidden="true" > <div className="modal-dialog modal"> <div className="modal-content" style={{ overflow: 'hidden' }}> <div className="modal-header"> {title} <button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div className="modal-body">{children}</div> </div> </div> </div> ); });
第二步:在父组件中处理点击逻辑
import { useRef, useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; import { ModalWrapper } from './ModalWrapper'; const YourParentComponent = () => { const modalRef = useRef(null); const navigate = useNavigate(); const handleNavAndClose = useCallback((targetPath) => { // 关闭模态框 const modalElement = modalRef.current; if (modalElement) { const bootstrapModal = window.bootstrap.Modal.getInstance(modalElement); bootstrapModal?.hide(); } // 执行路由导航 navigate(targetPath); }, [navigate]); return ( <ModalWrapper ref={modalRef} title="你的模态框标题" modalName="example" > {/* 用自定义按钮替代原生Link */} <button onClick={() => handleNavAndClose('/target-page')} className="btn btn-link text-decoration-none" // 模拟Link样式 > 点击跳转并关闭模态框 </button> </ModalWrapper> ); };
方案3:用React状态完全控制模态框(最符合React范式)
如果不想依赖Bootstrap的JS逻辑,可以完全用React状态来控制模态框的显示/隐藏,路由变化时自动切换状态:
修改ModalWrapper为受控组件
import { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; export const ModalWrapper = (props) => { const { children, title, modalName, isOpen, onClose } = props; const location = useLocation(); // 路由变化时触发关闭 useEffect(() => { if (isOpen) onClose(); }, [location, isOpen, onClose]); return ( <div className={`modal fade ${isOpen ? 'show' : ''}`} id={`modal-${modalName}`} tabIndex="-1" role="dialog" aria-labelledby="modal-label" aria-hidden={!isOpen} style={{ display: isOpen ? 'block' : 'none' }} > <div className="modal-dialog modal"> <div className="modal-content" style={{ overflow: 'hidden' }}> <div className="modal-header"> {title} <button type="button" className="btn-close" onClick={onClose} aria-label="Close"></button> </div> <div className="modal-body"> {children} <Link to="/target-page">点击跳转,模态框自动关闭</Link> </div> </div> </div> </div> ); };
父组件中控制状态
import { useState } from 'react'; import { ModalWrapper } from './ModalWrapper'; const ParentComponent = () => { const [isModalOpen, setIsModalOpen] = useState(false); return ( <> <button onClick={() => setIsModalOpen(true)}>打开模态框</button> <ModalWrapper title="标题" modalName="example" isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} > {/* 模态框内容 */} </ModalWrapper> </> ); };
内容的提问来源于stack exchange,提问作者Rinat Hatipov
相关产品推荐
相关产品推荐

