You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

问题根源

  1. 状态更新异步性与闭包问题:React的useState更新是异步的,计算完成后exp被设为32.5,点击清空按钮时调用的setstate('', '0',true)还未完成状态更新,此时click函数中的exp依然捕获的是旧值32.5,导致按下5时执行exp + '5'得到32.55。
  2. 清空逻辑冗余:清空按钮中连续调用两次setstate('', '0',true),不仅造成不必要的重渲染,还可能引发状态更新冲突。
  3. 计算后输入未重置:当计算完成(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 00:03:12