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
相关产品推荐
相关产品推荐

