React中如何在超时后设置state?轮盘组件spinning状态异常
问题原因分析
你的问题出在异步代码的时序逻辑上:
setTimeout是异步任务,循环中所有的setTimeout回调会被加入事件队列,等待当前同步代码执行完毕后才会依次触发。- 你在循环结束后立刻调用
setSpinning(false),这行同步代码会在所有setTimeout回调执行前就运行,把spinning设为false。但后续每个setTimeout回调里又会调用setSpinning(true),最终导致spinning始终停留在true状态。
另外,直接用document.getElementById修改DOM样式不符合React的设计理念,应该用状态来管理样式属性。
修复后的代码
import React, { useState } from "react"; const numbers = [ 0, 32, 15, 19, 4, 21, 2, 25, 17, 34, 6, 27, 13, 36, 11, 30, 8, 23, 10, 5, 24, 16, 33, 1, 20, 14, 31, 9, 22, 18, 29, 7, 28, 12, 35, 3, 26, ]; const green = [0]; const red = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36]; const black = [2, 4, 6, 8, 10, 11, 13, 15, 17, 20, 22, 24, 26, 28, 29, 31, 33, 35]; const RouletteWheel = () => { const [number, setNumber] = useState(0); const [spinning, setSpinning] = useState(false); const [numberColor, setNumberColor] = useState("green"); // 新增颜色状态 const getRandomNumber = () => { return numbers[Math.floor(Math.random() * numbers.length)]; }; const spin = () => { const targetNum = getRandomNumber(); const totalSteps = numbers.length * 2 + numbers.indexOf(targetNum) + 1; setSpinning(true); // 一开始就标记为旋转状态 for (let j = 0; j < totalSteps; j++) { setTimeout(() => { const currentNum = numbers[j % numbers.length]; // 根据当前数字设置颜色状态 if (green.includes(currentNum)) { setNumberColor("green"); } else if (red.includes(currentNum)) { setNumberColor("red"); } else { setNumberColor("black"); } setNumber(currentNum); // 最后一步执行完成后,结束旋转状态 if (j === totalSteps - 1) { setTimeout(() => setSpinning(false), 0); } }, j * 1.25); // 调整延迟计算,避免动画等待时间指数级增长 } }; return ( <div className="roulette"> <h1 id="numberDisp" style={{ color: numberColor }}>{number}</h1> <button onClick={spin} disabled={spinning}> {spinning ? "Spinning..." : "Spin the wheel!"} </button> </div> ); }; export default RouletteWheel;
关键修改点
修正异步时序:
- 旋转开始时立刻调用
setSpinning(true),明确标记轮盘状态。 - 在最后一个
setTimeout回调中,额外添加延迟任务(即使延迟0也能确保DOM更新完成),将spinning设为false,保证动画完全结束后再更新状态。
- 旋转开始时立刻调用
用状态管理样式:
- 新增
numberColor状态控制数字颜色,替代直接操作DOM的方式,符合React单向数据流原则。
- 新增
优化动画延迟:
- 原代码中
j * (j * 1.25)会导致延迟时间指数级增长,改成j * 1.25让动画匀速过渡,避免后续步骤等待时间过长。
- 原代码中
内容的提问来源于stack exchange,提问作者Zach
相关产品推荐
相关产品推荐

