React计算器calculate函数报错:Cannot read properties of undefined (reading 'length')
React计算器点击等号触发TypeError问题排查与修复
错误核心原因
点击等号按钮时触发TypeError: Cannot read properties of undefined (reading 'length'),同时控制台无日志输出,根源有两个:
- 参数未传递:等号点击事件中调用
calculate()时未传入组件的storeArr状态,导致函数内的storeArr参数为undefined,访问storeArr.length直接报错。 - 无限递归:
calculate函数内部执行console.log(calculate(storeArr)),会无限递归调用自身,不仅无法输出日志,还会引发栈溢出,阻断正常执行流程。
其他潜在问题
click函数中重复调用setActiveKey(selector),且直接依赖activeKey旧值判断(if (activeKey !== "=")),由于React状态更新是异步的,这里的判断逻辑可能不符合预期。- 计算完成后未将结果同步更新到组件状态,无法在界面展示计算结果。
修复步骤
- 传递正确参数:等号按钮点击时,传入组件的
storeArr状态:onClick={() => { if (i.text === "=") { calculate(storeArr); } else { click(i.text); } }} - 移除递归调用:将
calculate内的递归调用改为打印最终结果:// 替换 console.log(calculate(storeArr)); console.log("计算结果:", storeArr[0]); - 修复
click函数逻辑:使用函数式更新获取最新状态,避免重复setState:function click(selector) { setActiveKey(selector); if (selector !== "=") { // 直接判断传入的selector,而非依赖可能过期的activeKey setStoreArr(prev => [...prev, selector]); } } - 同步计算结果到状态:计算完成后更新
storeArr和activeKey,展示结果:function calculate(inputArr) { // 先复制一份数组,避免直接修改原状态数组 const storeArr = [...inputArr]; // ...原有计算逻辑 const result = storeArr[0]; console.log("计算结果:", result); // 更新状态展示结果 setStoreArr([result]); setActiveKey(result); return result; }
完整修复代码
import { useState } from 'react'; export default function App() { const [activeKey, setActiveKey] = useState(0); const [storeArr, setStoreArr] = useState([]); function click(selector) { setActiveKey(selector); if (selector !== "=") { setStoreArr(prev => [...prev, selector]); } } function clear() { setStoreArr([]); setActiveKey(0); } function calculate(inputArr) { if (!inputArr || inputArr.length === 0) return; // 复制数组,避免修改原状态 const storeArr = [...inputArr]; // 合并连续数字 for (let i = 0; i < storeArr.length; i++) { if ( typeof storeArr[i] === "number" && typeof storeArr[i + 1] === "number" ) { storeArr[i] = storeArr[i] * 10 + storeArr[i + 1]; storeArr.splice(i + 1, 1); i--; } } // 先处理乘除 for (let i = 0; i < storeArr.length; i++) { if (storeArr[i] === "x") { storeArr[i - 1] = storeArr[i - 1] * storeArr[i + 1]; storeArr.splice(i, 2); i--; } else if (storeArr[i] === "/") { storeArr[i - 1] = storeArr[i - 1] / storeArr[i + 1]; storeArr.splice(i, 2); i--; } } // 再处理加减 for (let i = 0; i < storeArr.length; i++) { if (storeArr[i] === "+") { storeArr[i - 1] = storeArr[i - 1] + storeArr[i + 1]; storeArr.splice(i, 2); i--; } else if (storeArr[i] === "-") { storeArr[i - 1] = storeArr[i - 1] - storeArr[i + 1]; storeArr.splice(i, 2); i--; } } const result = storeArr[0]; console.log("计算结果:", result); // 更新状态展示结果 setStoreArr([result]); setActiveKey(result); return result; } const topFuncs = [ { name: "clear", text: "AC" }, { name: "divide", text: "/" } ]; const numsDiv = [ { name: "seven", text: 7 }, { name: "eight", text: 8 }, { name: "nine", text: 9 }, { name: "four", text: 4 }, { name: "five", text: 5 }, { name: "six", text: 6 }, { name: "one", text: 1 }, { name: "two", text: 2 }, { name: "three", text: 3 }, { name: "zero", text: 0 }, { name: "decimal", text: "." } ]; const rightDiv = [ { name: "multiply", text: "x" }, { name: "subtract", text: "-" }, { name: "add", text: "+" }, { name: "equals", text: "=" } ]; return ( <div className="App"> <div id="outer-div" className="outer-div"> <div className="store-display">{storeArr}</div> <div id="display" className="display"> {activeKey} </div> <div className="left-right"> <div id="left-div" className="left-div"> <div className="top-funcs"> {topFuncs.map((i) => ( <button id={i.name} className="btn" key={i.text} onClick={() => { if (i.text === "AC") { return clear(); } else { click(i.text); } }} > {i.text} </button> ))} </div> <div id="nums-div"> {numsDiv.map((i) => ( <button id={i.name} className="btn" key={i.text} onClick={() => click(i.text)} > {i.text} </button> ))} </div> </div> <div id="right-div" className="right-div"> {rightDiv.map((i) => ( <button id={i.name} className="btn" key={i.text} onClick={() => { if (i.text === "=") { calculate(storeArr); } else { click(i.text); } }} > {i.text} </button> ))} </div> </div> </div> </div> ); }
内容的提问来源于stack exchange,提问作者Gabi
相关产品推荐
相关产品推荐

