You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 01:30:59