React结合Immer produce时onmouseenter/onmouseleave离开状态不更新问题
问题原因与解决方法
核心问题
你当前的代码里所有层级的div共用了同一个isHover状态,再加上DOM事件冒泡的影响,就会出现只有外层div生效的情况:鼠标移入内层div时,事件会冒泡到外层,状态被外层的事件处理覆盖;鼠标从内层移到外层时,内层的onMouseLeave触发会把状态改成false,导致外层的背景色也跟着变回初始值,完全不符合预期。
解决办法
方法一:给每个可交互div单独维护状态(推荐)
把需要hover效果的div封装成独立组件,每个组件自己管理hover状态,互不干扰:
import { useState } from 'react'; const HoverBox = ({ children, baseStyle }) => { const [isHover, setIsHover] = useState(false); return ( <div style={{ ...baseStyle, backgroundColor: isHover ? 'red' : 'initial' }} onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)} > {children} </div> ); }; // 父组件里这样用 export default function App() { return ( <HoverBox baseStyle={{ padding: '20px', border: '1px solid #000' }}> 外层div <HoverBox baseStyle={{ padding: '20px', border: '1px solid blue', marginTop: '10px' }}> 中间层div <HoverBox baseStyle={{ padding: '20px', border: '1px solid green', marginTop: '10px' }}> 最内层div </HoverBox> </HoverBox> </HoverBox> ); }
方法二:用对象维护多元素状态+阻止事件冒泡
如果不想封装组件,也可以用对象来存储每个div的hover状态,同时在事件处理里阻止冒泡:
import { useState } from 'react'; export default function App() { // 用对象存每个div的hover状态 const [hoverStatus, setHoverStatus] = useState({ outer: false, middle: false, inner: false }); const handleEnter = (key, e) => { e.stopPropagation(); // 阻止事件冒泡到父元素 setHoverStatus(prev => ({ ...prev, [key]: true })); }; const handleLeave = (key, e) => { e.stopPropagation(); setHoverStatus(prev => ({ ...prev, [key]: false })); }; return ( <div style={{ padding: '20px', border: '1px solid #000', backgroundColor: hoverStatus.outer ? 'red' : 'initial' }} onMouseEnter={(e) => handleEnter('outer', e)} onMouseLeave={(e) => handleLeave('outer', e)} > 外层div <div style={{ padding: '20px', border: '1px solid blue', marginTop: '10px', backgroundColor: hoverStatus.middle ? 'red' : 'initial' }} onMouseEnter={(e) => handleEnter('middle', e)} onMouseLeave={(e) => handleLeave('middle', e)} > 中间层div <div style={{ padding: '20px', border: '1px solid green', marginTop: '10px', backgroundColor: hoverStatus.inner ? 'red' : 'initial' }} onMouseEnter={(e) => handleEnter('inner', e)} onMouseLeave={(e) => handleLeave('inner', e)} > 最内层div </div> </div> </div> ); }
为啥原来的写法失效?
- 所有div共用一个
isHover状态:不管哪个div触发hover,都会修改同一个状态,导致状态值被频繁覆盖,出现混乱。 - 事件冒泡:内层div的hover事件会传递到外层,外层的事件处理函数也会执行,进一步打乱状态的逻辑。
内容的提问来源于stack exchange,提问作者arannara
相关产品推荐
相关产品推荐

