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

React中setInterval更新的useState值在addEventListener中不更新求助

解决React中mousemove回调无法获取实时date状态的问题

问题根源

你的代码里,useEffect的依赖数组是空的,这意味着它只会在组件挂载时执行一次。onMouseMove函数形成了闭包,捕获的是组件挂载时的初始date状态值——即便setInterval每秒更新date,onMouseMove里始终只能拿到最初的那个date,自然无法显示实时时间。


解决方案1:将date加入useEffect依赖数组

每次date更新时,useEffect会重新执行,移除旧的mousemove监听,再绑定新的监听函数,新函数能捕获到最新的date值。同时把窗口宽高的计算移到useEffect内部,避免窗口大小变化后中心区域失效。

修改后的代码:

import { useState, useEffect } from 'react';

function App() {
  const [date, setDate] = useState(new Date());
  const [text, setText] = useState('');

  function refreshClock() {
    setDate(new Date());
  }

  useEffect(() => {
    const timerId = setInterval(refreshClock, 1000);  

    // 每次执行时重新计算窗口中心,适配窗口大小变化
    const windowHeight = window.innerHeight / 2;
    const windowWidth = window.innerWidth / 2;

    const onMouseMove = function(e) {
      const x = e.clientX;
      const y = e.clientY;

      if (x < windowWidth + 100 && x > windowWidth - 100 && y < windowHeight + 100 && y > windowHeight - 100 ) {
        setText(`${date.toLocaleTimeString('en-GB')}`);
      } else {
        setText('');
      }
    }

    window.addEventListener("mousemove", onMouseMove);

    return function cleanup() {
      clearInterval(timerId);
      window.removeEventListener("mousemove", onMouseMove);
    };
  }, [date]); // 添加date到依赖数组
  
  return (
    <>
      {text}
    </>
  )
}

export default App;

解决方案2:用useRef保存最新date(减少事件解绑绑定次数)

如果觉得每秒解绑再绑定mousemove事件冗余,可以用useRef存储最新的date值,这样无需频繁更新事件监听,直接在回调里取ref.current就能拿到实时状态。

修改后的代码:

import { useState, useEffect, useRef } from 'react';

function App() {
  const [date, setDate] = useState(new Date());
  const [text, setText] = useState('');
  const dateRef = useRef(date); // 用ref持久化最新date

  function refreshClock() {
    setDate(new Date());
  }

  // 监听date变化,实时更新ref的current值
  useEffect(() => {
    dateRef.current = date;
  }, [date]);

  useEffect(() => {
    const timerId = setInterval(refreshClock, 1000);  

    const windowHeight = window.innerHeight / 2;
    const windowWidth = window.innerWidth / 2;

    const onMouseMove = function(e) {
      const x = e.clientX;
      const y = e.clientY;

      if (x < windowWidth + 100 && x > windowWidth - 100 && y < windowHeight + 100 && y > windowHeight - 100 ) {
        // 从ref中获取最新的date
        setText(`${dateRef.current.toLocaleTimeString('en-GB')}`);
      } else {
        setText('');
      }
    }

    window.addEventListener("mousemove", onMouseMove);

    return function cleanup() {
      clearInterval(timerId);
      window.removeEventListener("mousemove", onMouseMove);
    };
  }, []); // 依赖数组为空,仅挂载时执行一次
  
  return (
    <>
      {text}
    </>
  )
}

export default App;

额外优化(可选)

如果需要支持窗口大小变化时实时更新中心区域,可以在useEffect里添加resize监听:

// 在useEffect内部添加
const handleResize = () => {
  // 若要实时更新窗口中心,可将windowHeight、windowWidth改为状态变量
};
window.addEventListener('resize', handleResize);

// 清理函数中移除监听
return () => {
  clearInterval(timerId);
  window.removeEventListener("mousemove", onMouseMove);
  window.removeEventListener('resize', handleResize);
};

内容的提问来源于stack exchange,提问作者Hanel Rhe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 18:01:20