如何避免子元素替换时onMouseEnter事件重复触发?
问题原因
点击切换国家时,父div内的子元素会被完全替换(比如<US>+<p>EN</p>换成<EG>+<p>AR</p>),触发组件重渲染。此时如果鼠标还停留在原图标位置,浏览器会把新挂载的图标识别成“新的悬停目标”,再次触发父元素的onMouseEnter事件,导致handleHover被重复调用,opacity又变回0.5。
解决方案
最直接可靠的方式是用CSS伪类替代JS事件控制悬停效果,彻底规避重渲染带来的事件重复触发问题:
- 删除JS里的
handleHover、handleNoHover函数,以及languageButtonStyle中的opacity状态管理 - 给父div的CSS类
header-right-side-language添加hover样式:
.header-right-side-language { opacity: 1; transition: opacity 0.2s; /* 可选,添加过渡动画提升体验 */ } .header-right-side-language:hover { opacity: 0.5; }
- 简化后的组件代码:
<div className="header-right-side-language" onClick={handleCountrySwitch}> {currentCountry === 'US' ? <> <US title="United States"/> <p>EN</p> </> : <> <EG title="Egypt"/> <p>AR</p> </> } </div>
- 简化后的切换函数:
const handleCountrySwitch = () => { setCurrentCountry((prevCountry) => (prevCountry === 'US' ? 'EG' : 'US')); };
如果必须保留JS控制逻辑(比如有复杂的悬停交互需求),可以用useRef记录鼠标状态:
import { useRef, useState } from 'react'; // ... const isHoveringRef = useRef(false); const [currentCountry, setCurrentCountry] = useState('US'); const [languageButtonStyle, setLanguageButtonStyle] = useState({ opacity: 1 }); const handleCountrySwitch = () => { setCurrentCountry((prevCountry) => (prevCountry === 'US' ? 'EG' : 'US')); // 仅当鼠标未悬停时重置opacity if (!isHoveringRef.current) { setLanguageButtonStyle((prevStyle) => ({ ...prevStyle, opacity: 1 })); } }; const handleHover = () => { isHoveringRef.current = true; setLanguageButtonStyle((prevStyle) => ({ ...prevStyle, opacity: 0.5 })); }; const handleNoHover = () => { isHoveringRef.current = false; setLanguageButtonStyle((prevStyle) => ({ ...prevStyle, opacity: 1 })); };
通过isHoveringRef记录真实的悬停状态,重渲染后就不会错误触发重复的悬停逻辑。
内容的提问来源于stack exchange,提问作者ZisIzHell
相关产品推荐
相关产品推荐

