React点击器游戏:如何解决useState状态显示跳变问题?
问题分析与修复方案
核心问题原因
- 多个定时器同时运行:
setInterval直接写在组件函数内部,每次组件渲染(状态变化时)都会创建新的定时器,多个定时器同时修改状态,导致数值跳变。 - 闭包陷阱导致状态更新错误:直接使用
findWorkCount + 1这种方式更新状态时,依赖的是当前渲染周期的旧状态值,当多个更新操作叠加时,会基于旧值重复计算,导致状态不符合预期。
修复后的代码
import { useState, useEffect } from 'react'; function App() { const [findWorkCount, setfindWorkCount] = useState(0); useEffect(() => { // 仅在组件挂载时创建一次定时器 const timer = setInterval(() => { setfindWorkCount(prevCount => { // 基于最新状态计算新值,进度满100%后重置为0 return prevCount >= 100 ? 0 : prevCount + 1; }); }, 500); // 组件卸载时清理定时器,避免内存泄漏 return () => clearInterval(timer); }, []); // 空依赖数组确保仅执行一次 return ( <div className="App"> <button onClick={() => { // 按钮点击也用函数式更新,规避闭包问题 setfindWorkCount(prevCount => { const newCount = prevCount + 11; return newCount >= 100 ? 0 : newCount; }); }} > Find Job </button> <div className="bar"> <div className="fillwork" style={{ width: `${findWorkCount}%` }}> <div className="counter">{findWorkCount}%</div> </div> </div> </div> ); } export default App;
关键修改点说明
- 用useEffect管理定时器生命周期:把定时器创建逻辑放到
useEffect中,空依赖数组确保组件挂载仅执行一次;同时添加清理函数,在组件卸载时销毁定时器,避免多个定时器冲突和内存泄漏。 - 函数式状态更新:调用
setfindWorkCount时传入回调函数,每次都基于最新的状态值计算新值,彻底解决闭包导致的旧状态复用问题。 - 统一状态重置逻辑:将自动增长和按钮点击的重置条件统一为
>=100时归零,让进度条的行为保持一致,符合视觉预期。
内容的提问来源于stack exchange,提问作者MrSnippet
相关产品推荐
相关产品推荐

