如何使用useEffect Hook实现鼠标移出窗口时模态框仅弹窗一次?
实现鼠标移出窗口仅弹出一次模态框
方案一:触发后立即移除事件监听
直接在第一次触发弹窗后移除mouseleave事件监听,后续鼠标移出操作就不会再触发弹窗:
React.useEffect(() => { const popupWhenLeave = (event) => { if ( event.clientY <= 0 || event.clientX <= 0 || event.clientX >= window.innerWidth || event.clientY >= window.innerHeight ) { handleClickOpen(); // 触发弹窗后立即移除监听,避免重复触发 document.removeEventListener("mouseleave", popupWhenLeave); } }; document.addEventListener("mouseleave", popupWhenLeave); // 组件卸载时清理监听 return () => { document.removeEventListener("mouseleave", popupWhenLeave); }; }, []);
方案二:使用useRef标记弹窗状态
如果需要保留监听(比如后续有重置需求),可以用useRef记录弹窗是否已触发,避免重复执行:
const hasTriggeredPopup = useRef(false); React.useEffect(() => { const popupWhenLeave = (event) => { if ( event.clientY <= 0 || event.clientX <= 0 || event.clientX >= window.innerWidth || event.clientY >= window.innerHeight ) { // 仅当未触发过弹窗时执行 if (!hasTriggeredPopup.current) { handleClickOpen(); hasTriggeredPopup.current = true; } } }; document.addEventListener("mouseleave", popupWhenLeave); return () => { document.removeEventListener("mouseleave", popupWhenLeave); }; }, []);
之前方案失效的原因
- 第一段代码频繁触发:没有任何限制逻辑,每次
mouseleave事件都会执行handleClickOpen。 - 第二段代码加
cursorOut状态但依赖为空数组:setCursorOut(true)会触发组件重新渲染,但useEffect依赖为空不会重新执行,事件监听依然存在,所以还是会重复触发。 - 添加
[cursorOut]依赖后弹窗不弹出:cursorOut变为true时,useEffect重新执行,此时if(!cursorOut)不成立不会添加新监听,同时返回函数会移除旧监听,导致后续无监听触发弹窗;且第一次触发时cursorOut的更新是异步的,可能还未完成就再次触发事件。
内容的提问来源于stack exchange,提问作者Krishna Thorat
相关产品推荐
相关产品推荐

