React中useState配合setInterval实现组件移动时计数异常问题
React组件移动异常:状态递增与日志输出不符的原因
作为React新手,我想实现一个持续移动的组件,通过递增transform: translate的坐标值来实现,但状态递增结果和日志输出不符合预期。
我的代码如下:
function Point() { const [countX, setCountX] = useState(0); const [countY, setCountY] = useState(0); setInterval(() => { setCountX((count) => count + 1); setCountY((count) => count + 1); console.log(countX + ":" + countY); }, 500); const styles = { transform: `translate(${countX}px,${countY}px)`, }; return <PointStyle style={styles} />; }
控制台输出的日志如下:
0:0 1:1 0:0 2:2 1:1 4:4 0:0 5:5 2:2 7:7 1:1 9:9 4:4 10:10 11:11 0:0 12:12 5:5 14:14 2:2 7:7
问题原因
- 多个定时器同时运行:每次组件状态更新都会触发重渲染,你直接在组件函数里调用
setInterval,导致每次渲染都新建一个定时器。这些定时器会同时修改状态,造成数值混乱。 - 闭包捕获旧状态:定时器的回调函数是在组件某一次渲染时创建的,它捕获的是当时的
countX和countY值(也就是旧状态)。所以你在回调里打印的永远是创建该定时器时的旧状态,不是最新的状态值。
修复方案
用useEffect来管理定时器,确保只在组件挂载时创建一次,且卸载时清理:
import { useState, useEffect } from 'react'; function Point() { const [countX, setCountX] = useState(0); const [countY, setCountY] = useState(0); useEffect(() => { const timer = setInterval(() => { setCountX(prev => prev + 1); setCountY(prev => prev + 1); }, 500); // 组件卸载时清除定时器 return () => clearInterval(timer); }, []); // 空依赖数组,只执行一次 const styles = { transform: `translate(${countX}px,${countY}px)`, }; return <PointStyle style={styles} />; }
如果需要打印最新的状态值,可以额外加一个useEffect来监听状态变化:
useEffect(() => { console.log(countX + ":" + countY); }, [countX, countY]); // 当countX或countY变化时执行
内容的提问来源于stack exchange,提问作者Yhoan
相关产品推荐
相关产品推荐

