我正在 React 中开发一个计算器应用程序。我面临一些奇怪的问题。
问题出在computeResult()函数上。代码逻辑是将数字和运算符插入 calculationArray
中,当用户单击 =
按钮时,调用 computeResult()
函数.
我遇到的第一个问题是,当用户点击=
按钮时,最后输入的数字或最后一个运算符之后的最新表达式
需要被插入计算数组
。我发现 setState 是异步的,因此我通过将最后一个“表达式”与 calculationArray
连接起来创建了一个新数组 tempcalculationArray
。然后使用 for
循环计算总数。 total
已从 for
循环内部记录到控制台。
然后第二个问题出现了,for
循环之后的console.log
不起作用。
第三个问题是 for
循环之后的 setState
也不起作用。
这是代码:
const Calculator = React.createClass({
getInitialState() {
return {
expression: "",
calculationArray: [],
answer: 0,
waitingForOperator: true,
};
},
inputDigit(val) {
const { expression, valueHolder, operator, waitingForOperator } = this.state;
this.setState({
expression: expression === "0" ? String(val) : expression + String(val),
waitingForOperator:true
});
},
inputDot() {
const { expression } = this.state;
if (expression.indexOf(".") == -1) {
this.setState({
expression: expression=="" ? "0." :expression + "."
});
}
},
inputSign() {
const { expression } = this.state;
if (expression.charAt(0) == "-") {
this.setState({
expression: expression.substr(1)
});
} else {
this.setState({
expression: "-" + expression
});
}
},
clearAll() {
const { expression , calculationArray, answer} = this.state;
this.setState({
expression: "",
calculationArray: [],
answer: 0
});
},
backSpace() {
const { expression } = this.state;
this.setState({
expression: expression.substr(0, expression.length - 1)
});
},
percent() {
const { expression } = this.state;
this.setState({
expression: String(Number(expression)/100)
});
},
inputOperator(oper) {
const { expression, calculationArray, waitingForOperator} = this.state;
if(waitingForOperator){
this.setState({
calculationArray: calculationArray.concat(expression).concat(oper),
expression:"",
waitingForOperator:false
});
}
},
computeResult() {
const { expression, calculationArray, waitingForOperator, answer} = this.state;
var arithmetic = {
'+': function (x, y) { return x + y },
'-': function (x, y) { return x - y },
'*': function (x, y) { return x * y },
'/': function (x, y) { return x / y },
};
var total = Number(calculationArray[0]);
var tempcalculationArray = calculationArray.concat(expression);
console.log(tempcalculationArray);
for(var i=1; i<=tempcalculationArray.length; i=i+2){
total = arithmetic[tempcalculationArray[i]](total, Number(tempcalculationArray[i+1]));
console.log(total);
}
console.log( "why I am not getting printed on console");
this.setState({
calculationArray: calculationArray.concat(expression),
waitingForOperator:false,
answer: total
});
},
render() {
const { expression, answer, math } = this.state;
const { updateExpression, computeResult } = this;
return (
<div>
<div id="displayarea">
<div id="equation"><p>{expression}</p></div>
<div id="answer"><p>{answer}</p></div>
</div>
<div id="calculatorpanel">
<div className="row">
<button className="btn" onClick={() => this.clearAll()}>AC</button>
<button className="btn" onClick={() => this.backSpace()}>←</button>
<button className="btn" onClick={() => this.inputOperator("/")}>÷</button>
<button className="btn" onClick={() => this.inputOperator("*")}>X</button>
</div>
<div className="row">
<button className="btn" onClick={() => this.inputDigit(7)}>
7
</button>
<button className="btn" onClick={() => this.inputDigit(8)}>
8
</button>
<button className="btn" onClick={() => this.inputDigit(9)}>
9
</button>
<button className="btn" onClick={() => this.inputOperator("-")}>-</button>
</div>
<div className="row">
<button className="btn" onClick={() => this.inputDigit(4)}>
4
</button>
<button className="btn" onClick={() => this.inputDigit(5)}>
5
</button>
<button className="btn" onClick={() => this.inputDigit(6)}>
6
</button>
<button className="btn" onClick={() => this.inputOperator("+")}>+</button>
</div>
<div className="row">
<button className="btn" onClick={() => this.inputDigit(1)}>
1
</button>
<button className="btn" onClick={() => this.inputDigit(2)}>
2
</button>
<button className="btn" onClick={() => this.inputDigit(3)}>
3
</button>
<button className="btn" onClick={() => this.percent()}>%</button>
</div>
<div className="row">
<button className="btn" onClick={() => this.inputDigit(0)}>
0
</button>
<button className="btn" onClick={() => this.inputSign()}>±</button>
<button className="btn" onClick={() => this.inputDot()}>.</button>
<button className="btn" onClick={() => this.computeResult()}>=</button>
</div>
</div>
<pre>{JSON.stringify(this.state, null, 2)}</pre>
</div>
);
}
});
ReactDOM.render(<Calculator />, document.getElementById("calculator"));
#equation { border: 1px solid #ee82ee; }
#answer { border: 1px solid #00f; }
p { height: 1em; margin: 0; padding: .5em; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="calculator"></div>
注意:在有人否决这个问题之前,请注意我已经彻底搜索了 stackflow 问题并阅读了其中的大部分内容,大多数答案并不适用于我的场景。另外,这个问题不可能重复,因为我正在寻找更好的方法来解决这个特定问题。
最佳答案
Then the second problem occurred, the
console.log
after the for loop was not working.The third issue is the setState after the for loop is also not working.
我喜欢 CodePen,但它的控制台有点糟糕。特别是,它不会报告错误。如果您打开浏览器的内置 JavaScript 控制台并运行代码,当您单击 =
时,您会看到类似这样的错误。按钮:
Uncaught TypeError: arithmetic[tempcalculationArray[i]] is not a function
这就是第二个问题和第三个问题的原因:当抛出错误时,您的代码将停止。
原因在这里:
for(var i=1; i<=tempcalculationArray.length; i=i+2){
total = arithmetic[tempcalculationArray[i]](total, Number(tempcalculationArray[i+1]));
// ...
这个for
循环将运行只要 i
小于或等于templcalcuationArray.length
。如果i
等于数组的长度,它大于数组中最后一个元素的索引,并且 tempcalculationArray[i]
下一行将返回 undefined
,和undefined
不是一个函数。
解决方案是使用<
运算符而不是 <=
:
for (var i = 1; i < tempcalculationArray.length; i += 2) {
这是一个工作片段:
const Calculator = React.createClass({
getInitialState() {
return {
expression: "",
calculationArray: [],
answer: 0,
waitingForOperator: true,
};
},
inputDigit(val) {
const { expression, valueHolder, operator, waitingForOperator } = this.state;
this.setState({
expression: expression === "0" ? String(val) : expression + String(val),
waitingForOperator:true
});
},
inputDot() {
const { expression } = this.state;
if (expression.indexOf(".") == -1) {
this.setState({
expression: expression=="" ? "0." :expression + "."
});
}
},
inputSign() {
const { expression } = this.state;
if (expression.charAt(0) == "-") {
this.setState({
expression: expression.substr(1)
});
} else {
this.setState({
expression: "-" + expression
});
}
},
clearAll() {
const { expression , calculationArray, answer} = this.state;
this.setState({
expression: "",
calculationArray: [],
answer: 0
});
},
backSpace() {
const { expression } = this.state;
this.setState({
expression: expression.substr(0, expression.length - 1)
});
},
percent() {
const { expression } = this.state;
this.setState({
expression: String(Number(expression)/100)
});
},
inputOperator(oper) {
const { expression, calculationArray, waitingForOperator} = this.state;
if(waitingForOperator){
this.setState({
calculationArray: calculationArray.concat(expression).concat(oper),
expression:"",
waitingForOperator:false
});
}
},
computeResult() {
const { expression, calculationArray, waitingForOperator, answer} = this.state;
var arithmetic = {
'+': function (x, y) { return x + y },
'-': function (x, y) { return x - y },
'*': function (x, y) { return x * y },
'/': function (x, y) { return x / y },
};
var total = Number(calculationArray[0]);
var tempcalculationArray = calculationArray.concat(expression);
console.log(tempcalculationArray);
for(var i=1; i<tempcalculationArray.length; i=i+2){
console.log(i, tempcalculationArray[i]);
total = arithmetic[tempcalculationArray[i]](total, Number(tempcalculationArray[i+1]));
console.log(total);
}
console.log( "why I am not getting printed on console");
this.setState({
calculationArray: calculationArray.concat(expression),
waitingForOperator:false,
answer: total
});
},
render() {
const { expression, answer, math } = this.state;
const { updateExpression, computeResult } = this;
return (
<div>
<div id="displayarea">
<div id="equation"><p>{expression}</p></div>
<div id="answer"><p>{answer}</p></div>
</div>
<div id="calculatorpanel">
<div className="row">
<button className="btn" onClick={() => this.clearAll()}>AC</button>
<button className="btn" onClick={() => this.backSpace()}>←</button>
<button className="btn" onClick={() => this.inputOperator("/")}>÷</button>
<button className="btn" onClick={() => this.inputOperator("*")}>X</button>
</div>
<div className="row">
<button className="btn" onClick={() => this.inputDigit(7)}>
7
</button>
<button className="btn" onClick={() => this.inputDigit(8)}>
8
</button>
<button className="btn" onClick={() => this.inputDigit(9)}>
9
</button>
<button className="btn" onClick={() => this.inputOperator("-")}>-</button>
</div>
<div className="row">
<button className="btn" onClick={() => this.inputDigit(4)}>
4
</button>
<button className="btn" onClick={() => this.inputDigit(5)}>
5
</button>
<button className="btn" onClick={() => this.inputDigit(6)}>
6
</button>
<button className="btn" onClick={() => this.inputOperator("+")}>+</button>
</div>
<div className="row">
<button className="btn" onClick={() => this.inputDigit(1)}>
1
</button>
<button className="btn" onClick={() => this.inputDigit(2)}>
2
</button>
<button className="btn" onClick={() => this.inputDigit(3)}>
3
</button>
<button className="btn" onClick={() => this.percent()}>%</button>
</div>
<div className="row">
<button className="btn" onClick={() => this.inputDigit(0)}>
0
</button>
<button className="btn" onClick={() => this.inputSign()}>±</button>
<button className="btn" onClick={() => this.inputDot()}>.</button>
<button className="btn" onClick={() => this.computeResult()}>=</button>
</div>
</div>
<pre>{JSON.stringify(this.state, null, 2)}</pre>
</div>
);
}
});
ReactDOM.render(<Calculator />, document.getElementById("calculator"));
#equation { border: 1px solid #ee82ee; }
#answer { border: 1px solid #00f; }
p { height: 1em; margin: 0; padding: .5em; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="calculator"></div>
关于javascript - 如何使React中的setState同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44790423/