UseRef无法选中DOM元素,点击Card编辑按钮无法唤起Bootstrap Modal
解决Bootstrap Modal ref为空及唤起问题
问题根源
你当前的代码存在几个关键问题:
- ref传递方式错误:Modal组件用了
forwardRef接收ref,但你在App里是通过btn={btn}作为普通props传递的,forwardRef的第二个参数是专门接收ref的通道,不是props,所以导致ref根本没绑定到按钮上。 - setState异步特性:你在
Add函数里刚调用Setli就立刻console.log(btn.current),此时新的Modal组件还没完成渲染,ref自然是空的。 - 固定Modal ID冲突:所有Modal都用同一个
id="staticBackdrop",多个Modal共存时会导致无法分别唤起。
修正方案
1. 先解决ref传递的基础问题
Modal组件用了forwardRef,所以App里必须通过ref属性传递,不能用props:
// App.js的Add函数里修改Modal调用方式 function Add(){ Setli(li=>[...li,<Model ref={btn}/>]) }
然后要等组件渲染完成再访问ref,用useEffect监听数组变化:
// App.js里新增useEffect useEffect(() => { if (li.length > 0) { console.log(btn.current); // 此时ref已绑定 } }, [li]);
2. 更优方案:直接用Bootstrap JS API控制Modal(无需依赖触发按钮)
没必要隐藏触发按钮绕弯子,直接用Bootstrap的Modal JS实例来控制显示/隐藏,更灵活可靠:
修改Modal.js
import React, { useRef, useEffect, forwardRef, useImperativeHandle } from "react"; import { Modal as BootstrapModal } from 'bootstrap'; const Model = forwardRef((props, ref) => { const modalDomRef = useRef(null); let bootstrapModalInstance = null; // 初始化Bootstrap Modal实例 useEffect(() => { bootstrapModalInstance = new BootstrapModal(modalDomRef.current); return () => bootstrapModalInstance.dispose(); // 组件卸载时清理 }, []); // 向父组件暴露唤起Modal的方法 useImperativeHandle(ref, () => ({ show: () => bootstrapModalInstance.show(), hide: () => bootstrapModalInstance.hide() })); return ( <div className="modal fade" ref={modalDomRef} data-bs-backdrop="static" data-bs-keyboard="false" tabIndex="-1" aria-labelledby={`modal-title-${props.id}`} aria-hidden="true" > <div className="modal-dialog"> <div className="modal-content"> <div className="modal-header"> <h5 className="modal-title" id={`modal-title-${props.id}`}> Modal title </h5> <button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close" ></button> </div> <div className="modal-body">编辑内容...</div> <div className="modal-footer"> <button type="button" className="btn btn-secondary" data-bs-dismiss="modal" > 取消 </button> <button type="button" className="btn btn-primary"> 保存 </button> </div> </div> </div> </div> ); }); export default Model;
修改App.js(支持多Modal管理)
function App() { const [modalList, setModalList] = useState([]); const modalRefs = useRef([]); // 用数组存储多个Modal的ref useEffect(() => { // 初始化第一个Card和Modal setModalList(prev => [...prev, { id: 0 }]); }, []); // 添加新的Card和Modal function Add() { const newId = modalList.length; setModalList(prev => [...prev, { id: newId }]); } // 唤起指定ID的Modal(Card组件可通过Context调用此方法) const openModal = (id) => { modalRefs.current[id]?.show(); }; return ( <> <CardContext.Provider value={{ Add, openModal }}> {modalList.map((item) => ( <div key={item.id}> {/* Card组件点击编辑按钮时调用openModal(item.id) */} <Card onEditClick={() => openModal(item.id)} /> <Model ref={el => modalRefs.current[item.id] = el} id={item.id} /> </div> ))} </CardContext.Provider> </> ); }
内容的提问来源于stack exchange,提问作者Mustafa Dahodwala
相关产品推荐
相关产品推荐

