React实现随机数滚动动画并与用户输入值对比的最佳方案
问题根因分析
- 你写的判断逻辑执行时机错误:
handleGenerateNumber里的if判断是点击按钮瞬间执行的,此时5秒的随机数滚动还没开始,对比的是点击前的旧随机数,自然不会触发预期逻辑 - React状态更新为异步批量处理:调用
setToggle、setRandomNumber之后,无法立即读取到最新的状态值,必须在状态更新完成后的钩子/回调中才能拿到最新值 - 额外注意:如果你的输入值是从
<input />表单获取的,默认是字符串类型,直接用===和数字类型的随机数对比会因为类型不一致判定不相等,需要先做类型转换
修正后的实现方案
核心逻辑:新增useEffect监听toggle状态,当toggle从true变为false时,说明5秒滚动已经停止,此时再执行两个数值的对比逻辑即可。
import { useState, useEffect } from 'react'; export default function RandomRoll() { const [randomNumber, setRandomNumber] = useState(0); const [toggle, setToggle] = useState(false); const [inputNum, setInputNum] = useState(0); // 控制随机数滚动逻辑 useEffect(() => { let counter; if (toggle) { counter = setInterval( () => setRandomNumber(Math.floor(Math.random() * 10)), 50 ); } return () => { clearInterval(counter); }; }, [toggle]); // 监听滚动停止事件,执行结果对比 useEffect(() => { // 仅当滚动从开启变为关闭时执行判断 if (!toggle) { if (inputNum === randomNumber) { console.log(randomNumber, "you won"); // 此处可添加自定义中奖逻辑 } } }, [toggle, inputNum, randomNumber]); const handleGenerateNumber = () => { setToggle(true); // 5秒后停止滚动 setTimeout(() => { setToggle(false); }, 5000); }; // 输入框绑定逻辑 const handleInputChange = (e) => { // 直接转成数字存储,避免后续类型判断问题 setInputNum(Number(e.target.value)); }; return ( <div> <input type="number" min="0" max="9" onChange={handleInputChange} value={inputNum} /> <div>当前随机数:{randomNumber}</div> <button onClick={handleGenerateNumber} disabled={toggle}>开始抽奖</button> </div> ) }
核心修改说明
- 新增了专门监听滚动停止的useEffect,依赖项包含toggle、inputNum、randomNumber,保证判断时拿到的都是最新值
- 输入框取值时直接转换为数字类型,避免类型不一致导致的判断失败
- 给按钮加了disabled状态,避免滚动过程中重复点击触发多次定时器
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

