React计算器点击运算符报too many renders错误如何解决?
问题根因
你遇到的无限重渲染报错和运算符不显示问题,根源是将状态更新逻辑直接写在了组件渲染主流程中:
- 组件函数主体(return语句之前的代码)属于渲染逻辑,每次组件重渲染都会逐行执行
- 当你点击+按钮调用
sum()修改operation为'+'后,组件触发重渲染,此时operation === "+"的判断成立,调用setValue()修改状态 - 状态更新又会触发新一轮重渲染,再次执行
setValue(),陷入无限循环,就抛出了too many re-renders错误
为什么clear函数能正常运行?
调用clear()时会把operation设为空字符串,所有判断运算类型的if分支都不会触发,不会执行setValue()更新状态,也就不会进入无限重渲染循环。
修复方案
你可以把自动运算的逻辑放到useEffect钩子中,只在依赖的firstValue、secondValue、operation变化时才执行运算,避免每次渲染都触发状态更新:
import React, { useState, useEffect } from "react"; const Calculator = () => { const [firstValue, setFirstValue] = useState('') const [secondValue, setSecondValue] = useState('') const [operation, setOperation] = useState('') const [value, setValue] = useState('') function sum() { setOperation('+') } // 其余运算符逻辑可以参照sum封装为单独函数,或者统一传参处理 function sub() { setOperation('-') } function mul() { setOperation('x') } function div() { setOperation('/') } function clear() { setFirstValue('') setSecondValue('') setOperation('') setValue('') } // 运算逻辑移入useEffect,仅依赖项变化时执行 useEffect(() => { // 两个输入框都有值才执行运算,避免NaN if (!firstValue || !secondValue || !operation) return const num1 = parseInt(firstValue) const num2 = parseInt(secondValue) switch(operation) { case '+': setValue(num1 + num2) break case '-': setValue(num1 - num2) break case 'x': setValue(num1 * num2) break case '/': setValue(num2 === 0 ? '除数不能为0' : num1 / num2) break default: return } }, [operation, firstValue, secondValue]) return ( <div className="calculator"> <div data-testid="name">Calculator</div> <div data-testid="display" className="display">{firstValue} {operation} {secondValue} {value ? `= ${value}` : ''}</div> <div className="number-inputs"> <input onChange={(e) => setFirstValue(e.target.value)} data-testid="num1" id="num1" type="number"></input> <div data-testid="selected-operation">{operation}</div> <input onChange={(e) => setSecondValue(e.target.value)} data-testid="num2" id="num2" type="number"></input> </div> <div className="operation-selectors"> <button onClick={sum} data-testid="add">+</button> <button onClick={sub} data-testid="sub">-</button> <button onClick={mul} data-testid="mul">x</button> <button onClick={div} data-testid="div">/</button> </div> <div className="options"> <button onClick={clear} data-testid="clear" className="clear"> Clear </button> <button data-testid="calc">Calculate</button> </div> <div data-testid="error" id="error" className="error"></div> </div> ); }; export default Calculator;
补充说明
你不需要额外处理类组件的挂载逻辑,useEffect已经覆盖了函数式组件的挂载、更新、卸载生命周期场景,本次问题和挂载逻辑无关。
另外点击事件的写法不用额外传e调用preventDefault,按钮的默认点击行为不会影响业务逻辑,直接写onClick={sum}即可。
内容的提问来源于stack exchange,提问作者Antonio contreras
相关产品推荐
相关产品推荐

