React实现的JavaScript计算器状态回退异常问题求助
React计算器状态异常问题修复
问题描述
我基于React开发了一款JavaScript计算器,遇到状态异常问题:计算表达式3+5*6-2/4得到结果32.5后,触发清空函数将状态设为空,但随后按下5时,状态回退至32.5并拼接为32.55。该问题并非首次测试就出现,目前正在使用fcc测试套件进行测试,尚未完成测试就遇到此问题。
代码实现
import React, { useState, useEffect } from 'react'; import './JavaScriptCalculator.css'; function JavaScriptCalculator() { const [exp, setExp] = useState(''); const [ans, setAns] = useState('0'); const [s, ss] = useState(true); function setstate(e, a, s = true,v='') { console.log(e, a, s,v); setExp(e); setAns(a); ss(s); } function click(v) { switch (v) { case 'A': setstate('', '0',true,v);setstate('', '0',true,v); break; case 'E': setstate(eval(exp), eval(exp), false,v); break; default: setstate(exp + v, '',true,v); break; } } return ( <div id="calculatorbackground"> <div id="calculator"> <div id="display"> <div id="Expression">{s && exp}</div><div id="Answere">{ans}</div> </div> <div onClick={() => click('A')} id="clear">AC</div> <div onClick={() => click('C')} id="back">{'-<'}</div> <div onClick={() => click('/')} data-value="/" id="divide">/</div> <div onClick={() => click('*')} data-value="*" id="multiply">x</div> <div onClick={() => click('7')} data-value="7" id="seven">7</div> <div onClick={() => click('8')} data-value="8" id="eight">8</div> <div onClick={() => click('9')} data-value="9" id="nine">9</div> <div onClick={() => click('-')} data-value="-" id="subtract">-</div> <div onClick={() => click('4')} data-value="4" id="four">4</div> <div onClick={() => click('5')} data-value="5" id="five">5</div> <div onClick={() => click('6')} data-value="6" id="six">6</div> <div onClick={() => click('+')} data-value="+" id="add">+</div> <div onClick={() => click('1')} data-value="1" id="one">1</div> <div onClick={() => click('2')} data-value="2" id="two">2</div> <div onClick={() => click('3')} data-value="3" id="three">3</div> <div onClick={() => click('E')} id="equals">=</div> <div onClick={() => click('0')} data-value="0" id="zero">0</div> <div onClick={() => click('.')} data-value="." id="decimal">.</div> <div onClick={() => click('L')}>L</div> </div> </div> ); } export default JavaScriptCalculator;
控制台日志
0 true A 0 true A 0 true A 0 true A 0 true A 0 true A 0 true A 0 true A 0 true A 0 true A 0 true A 0 true A 0 true A 0 true A 0 true A 5 true 5 5* true * 5*1 true 1 5*1+ true + 5*1+5 true 5 5*1+5+ true + 5*1+5+9 true 9 5*1+5+92 true 2 102 102 false 'E' 0 true A 0 true A 0 true A 0 true A 1 true 1 12 true 2 123 true 3 0 true A 0 true A 3 true 3 3+ true + 3+5 true 5 3+5* true * 3+5*6 true 6 3+5*6- true - 3+5*6-2 true 2 3+5*6-2/ true / 3+5*6-2/4 true 4 32.5 32.5 false 'E' 0 true A 0 true A 32.55 true 5 32.55- true - 32.55-9 true 9 32.55-9+ true + 32.55-9+5 true 5 28.549999999999997 28.549999999999997 false 'E' 0 true A 0 true A 0 true 0 00 true 0 000 true 0 0 true A 0 true A 5 true 5 5. true . 5.. true . 5..0 true 0 0 true A 0 true A 1 true 1 10 true 0 10. true . 10.5 true 5 10.5- true - 10.5-5 true 5 10.5-5. true . 10.5-5.5 true 5 5 5 false 'E' 0 true A 0 true A 55 true 5 55* true * 55*5 true 5 55*5. true . 55*5.5 true 5 302.5 302.5 false 'E' 0 true A 0 true A 5 true 5 5* true * 5*- true - 5*-5 true 5 -25 -25 false 'E' 0 true A 0 true A -255 true 5 -255* true * -255*- true - -255*-+ true + -255*-+5 true 5 1275 1275 false 'E' 0 true A 0 true A 5 true 5 5- true - 5-2 true 2 3 3 false 'E' 3/ true / 3/2 true 2 1.5 1.5 false 'E' 0 true A 0 true A 1.55 true 5 1.55+ true + 1.55+5 true 5 6.55 6.55 false 'E' 6.55+ true + 6.55+3 true 3 9.55 9.55 false 'E' 0 true A 0 true A 2 true 2 2/ true / 2/7 true 7 0.2857142857142857 0.2857142857142857 false 'E' 0 true A 0 true A
问题根源
- 状态更新异步性与闭包问题:React的
useState更新是异步的,计算完成后exp被设为32.5,点击清空按钮时调用的setstate('', '0',true)还未完成状态更新,此时click函数中的exp依然捕获的是旧值32.5,导致按下5时执行exp + '5'得到32.55。 - 清空逻辑冗余:清空按钮中连续调用两次
setstate('', '0',true),不仅造成不必要的重渲染,还可能引发状态更新冲突。 - 计算后输入未重置:当计算完成(
s=false)后,用户输入新数字时,应该开始新的表达式,而不是在旧结果上拼接,但当前代码直接执行exp + v,导致旧结果被复用。
修复方案
修改click函数的逻辑,解决上述问题:
function click(v) { switch (v) { case 'A': // 只调用一次状态更新,确保状态正确重置 setstate('', '0', true, v); break; case 'E': try { const result = eval(exp); setstate(result.toString(), result.toString(), false, v); } catch (err) { setstate('', 'Error', true, v); } break; default: // 如果是计算完成后输入新内容,直接设置为新值,而非拼接 const newExp = s ? exp + v : v; setstate(newExp, '', true, v); break; } }
修复说明
- 移除清空按钮中重复的
setstate调用,确保状态更新一次到位。 - 计算后输入新数字时,判断
s的状态:如果s为false(表示刚完成计算),则直接将exp设为当前输入的数字,开始新的表达式;否则正常拼接。 - 增加
eval的错误捕获,避免非法表达式导致崩溃。
内容的提问来源于stack exchange,提问作者Baljinder Singh
相关产品推荐
相关产品推荐

