React项目中Bootstrap模态框的hidden.bs.modal事件不触发怎么解决?
问题根因
- 事件绑定时机错误:你将
$('#exampleModal').on('hidden.bs.modal')直接写在函数组件顶层,组件执行渲染逻辑时模态框DOM还未挂载到页面,jQuery无法匹配到对应元素,事件绑定失效。 - 两套显隐逻辑冲突:你同时使用了Bootstrap原生的
data-toggle属性触发模态框,又用React的productImageHandler状态控制模态框的条件渲染,逻辑不同步导致原生事件无法正常触发。 - 组件直接卸载截断事件:你点击关闭按钮后直接将
productImageHandler设为false,模态框DOM会被立刻从页面移除,Bootstrap的关闭动画还未执行完,hidden.bs.modal事件根本没有触发机会。
修复方案
第一步:修改Modal.js代码
使用useEffect保证DOM挂载后再绑定事件,同时关联Bootstrap原生模态框方法和你的关闭逻辑:
import React, { useEffect } from 'react'; import $ from 'jquery'; const Modal = (props) => { // 组件挂载后初始化模态框、绑定事件 useEffect(() => { const $modal = $('#exampleModal'); // 初始化模态框,配置点击背景关闭 $modal.modal({ backdrop: true, // 允许点击背景关闭 show: true // 挂载后直接显示 }); // 绑定关闭完成事件 $modal.on('hidden.bs.modal', (e) => { console.log('模态框已关闭', e); props.onClose(false); }); // 组件卸载前清理事件、销毁模态框实例 return () => { $modal.off('hidden.bs.modal'); $modal.modal('dispose'); }; }, [props]); function onClickHandler(e) { fetch( 'http://reactapi.test/api/product/delete/' + e.target.attributes.guid.value, { method: 'get', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, } ) .then((response) => response.json()) .then((data) => { console.log(data); }); } function onModalDismissEvent(e) { // 调用Bootstrap原生关闭方法,会自动触发hidden.bs.modal事件 $('#exampleModal').modal('hide'); } return ( <div className='modal fade' id='exampleModal' tabIndex='-1' aria-labelledby='exampleModalLabel' aria-hidden='true' > <div className='modal-dialog'> <div className='modal-content'> <div className='modal-header'> <h5 className='modal-title' id='exampleModalLabel'> Resimler </h5> <button type='button' className='close' data-dismiss='modal' aria-label='Close' onClick={onModalDismissEvent} > <span aria-hidden='true'>×</span> </button> </div> <div className='modal-body'> {props.product.slider.map((e) => { return ( <div key={e.products_slider_guid}> <img height='150px' src={'http://example.test/' + e.image} alt={e.created_at} /> <button className='btn btn-outline-primary mr-2'> Update </button> <button onClick={onClickHandler} className='btn btn-outline-danger mr-2' guid={e.products_slider_guid} > Delete </button> </div> ); })} </div> <div className='modal-footer'> <button className='btn btn-outline-primary mr-4' type='button'> Save </button> </div> </div> </div> </div> ); }; export default Modal;
第二步:修改Main.js代码
删除触发按钮上的Bootstrap原生控制属性,避免和React状态逻辑冲突:
import React, { useContext, useState } from 'react'; import ProductContext from '../store/product-context'; import Modal from './Modal'; const Main = (props) => { const [productImageHandler, setProductImageHandler] = useState(false); const [findProductHandler, setFindProductHandler] = useState(''); const productCtx = useContext(ProductContext); const onClickHandler = (event) => { const findProduct = productCtx.items.find((item) => { return item.product_guid === event.target.attributes.guid.value; }); setFindProductHandler(findProduct); setProductImageHandler(true); }; const onCloseHandler = (e) => { setProductImageHandler(e); }; return ( <div> <main ref={(modal) => modal} role='main' className='container mt-5'> <div className='row'> <div className='col-xl-12'> {productCtx.items.map((item) => { return ( <div key={item.id} className='list-group'> <div className='list-group-item d-flex justify-content-between align-items-center'> {item.name} <div> <button className='btn btn-outline-info mr-2' // 删除原有的data-toggle和data-target属性 onClick={onClickHandler} guid={item.product_guid} > Images </button> <button className='btn btn-outline-danger mr-2'> Delete </button> </div> </div> </div> ); })} </div> </div> {productImageHandler && ( <Modal onClose={onCloseHandler} product={findProductHandler} /> )} </main> </div> ); }; export default Main;
修改后点击模态框背景、右上角关闭按钮都会触发hidden.bs.modal事件,且会同步更新React的显隐状态,逻辑完全对齐。
内容的提问来源于stack exchange,提问作者Okay Beydanol
相关产品推荐
相关产品推荐

