React 18中useState与useEffect重复执行问题求助
解决React中useEffect初始执行导致不必要输赢判定的问题
核心问题分析
你遇到的useEffect执行两次的情况,是React 18严格模式下的开发环境特性(生产环境只会执行一次),但核心痛点是页面初始加载时就触发了输赢判定——因为betMultiplier初始值为1,multiplier初始值为2,挂载时useEffect会直接执行判定逻辑。
最优解决方案:将判定逻辑直接整合到用户触发函数中
既然runMultiplier是用户主动操作(如下注按钮点击)才会调用的函数,完全不需要依赖useEffect监听状态更新做判定,直接在函数内部计算出新倍率后立即执行输赢判断即可,彻底避开初始挂载的问题:
const [betMultiplier, setBetMultiplier] = useState(1); const runMultiplier = () => { let layer = Math.random(); let i = 0; let newMultiplier; if (layer < 0.505) { newMultiplier = +(Math.random() * 1 + 1).toFixed(2); } else { while (layer > 0.5) { layer = Math.random(); if (layer < 0.5) break; i++; if (i > 17) { newMultiplier = 1000000; break; } } // 增加边界判断,避免i超出multiplierRange数组长度导致报错 if (!newMultiplier && multiplierRange[i]) { newMultiplier = +((Math.random() * (multiplierRange[i][1] - multiplierRange[i][0])) + multiplierRange[i][0]).toFixed(2); } } // 更新状态 setBetMultiplier(newMultiplier); // 直接执行输赢判定 if (multiplier >= newMultiplier) { console.log('you win!'); } else { console.log('you lose!'); } }; // 移除原有的useEffect
备选方案:保留useEffect但区分初始挂载与用户触发更新
如果因业务需求必须保留useEffect,可以用useRef标记是否为用户主动触发的更新,而非初始挂载:
const [betMultiplier, setBetMultiplier] = useState(1); const isUserTriggered = useRef(false); const runMultiplier = () => { isUserTriggered.current = true; let layer = Math.random(); let i = 0; if (layer < 0.505) { setBetMultiplier(+(Math.random()*1+1).toFixed(2)); } else { while (layer > 0.5) { layer = Math.random(); if (layer < 0.5) break; i++; if (i > 17) { setBetMultiplier(1000000); break; } } setBetMultiplier(+((Math.random()*(multiplierRange[i][1]-multiplierRange[i][0]))+multiplierRange[i][0]).toFixed(2)); } }; useEffect(() => { // 初始挂载时跳过判定 if (!isUserTriggered.current) return; if (multiplier >= betMultiplier) { console.log('you win!'); } else { console.log('you lose!'); } // 重置标记,避免非用户触发的更新误执行 isUserTriggered.current = false; }, [betMultiplier, multiplier]);
注意事项
- React 18严格模式的两次执行仅存在于开发环境,用于检测组件副作用是否符合预期,生产环境不会出现该情况;
- 注意
runMultiplier中i可能超出multiplierRange数组长度的情况,务必添加边界判断避免报错。
内容的提问来源于stack exchange,提问作者rt10
相关产品推荐
相关产品推荐

