为什么我必须点击两次才能触发事件?
Why do I have to click twice for an event to fire in react?
对于这个问题的简单性,我很抱歉,我是 React 的新手。我构建了一个带有两个输入字段的计算器,然后是用于处理不同计算的按钮。现在,我正在把它改造成一个功能更齐全的全键盘计算器。在我下面的代码中,我很确定我编写“onClick”函数的方式是问题所在,但我不确定它应该如何编写。 (示例中的大部分代码都与初始项目有关,与此问题无关,我只是想包括整个组件以备不时之需。)
当我点击“1”按钮时,控制台第一次记录 1,但页面顶部的 1 直到第二次点击才显示。在我第二次单击“1”按钮之前,我在这里发生了什么,不允许显示在顶部?
第一次点击:
App after first click on 1
第二次点击:
App after second click on 1
class Calculator extends React.Component {
constructor(props) {
super(props);
this.setNum1 = this.setNum1.bind(this);
this.setNum2 = this.setNum2.bind(this);
this.add = this.add.bind(this);
this.subtract = this.subtract.bind(this);
this.multiply = this.multiply.bind(this);
this.divide = this.divide.bind(this);
this.clear = this.clear.bind(this);
this.buttonPressed = this.buttonPressed.bind(this);
this.state = {
pressed: "",
result: "",
num1: "",
num2: "",
};
}
buttonPressed(e) {
e.preventDefault();
const pressed = e.target.name;
const result = this.state.pressed;
this.setState({ pressed });
this.setState({ result });
console.log(e.target.name);
}
setNum1(e) {
const num1 = e.target.value ? parseInt(e.target.value) : "";
this.setState({ num1 });
}
setNum2(e) {
const num2 = e.target.value ? parseInt(e.target.value) : "";
this.setState({ num2 });
}
add(e) {
e.preventDefault();
const result = this.state.num1 + this.state.num2;
this.setState({ result });
}
subtract(e) {
e.preventDefault();
const result = this.state.num1 - this.state.num2;
this.setState({ result });
}
multiply(e) {
e.preventDefault();
const result = this.state.num1 * this.state.num2;
this.setState({ result });
}
divide(e) {
e.preventDefault();
const result = this.state.num1 / this.state.num2;
this.setState({ result });
}
clear(e) {
e.preventDefault();
this.setState({ num1: "", num2: "", result: 0 });
}
render() {
const { num1, num2, result } = this.state;
return (
<div>
<h1>{this.state.result}</h1>
<input onChange={this.setNum1} value={num1}></input>
<input onChange={this.setNum2} value={num2}></input>
<br />
<button name="1" onClick={this.buttonPressed}>
1
</button>
<button onClick={this.add}>+</button>
<button onClick={this.subtract}>-</button>
<button onClick={this.multiply}>x</button>
<button onClick={this.divide}>/</button>
<button onClick={this.clear}>clear</button>
</div>
);
}
}
export default Calculator;
如果有人能帮助我了解我需要做些什么来解决这种情况,我将不胜感激!
这里的问题在
buttonPressed(e) {
e.preventDefault();
// here e.target.name is 1 so value in const pressed becomes 1
const pressed = e.target.name;
// currently this.state.pressed is "" so result becomes "" if you want to show
// first number as result use const result = e.target.name
const result = this.state.pressed;
this.setState({ pressed });
this.setState({ result });
console.log(e.target.name);
}
您将结果设置为 this.state.pressed,第一次为空,因此将结果设置为空字符串,但第二次 this.state.pressed 为 1,因此将结果设置为 1,因此它第二次点击显示
推理:
阻止导致问题
buttonPressed(e) {
e.preventDefault();
const pressed = e.target.name;
const result = this.state.pressed;
this.setState({ pressed });
this.setState({ result });
console.log(e.target.name);
}
原因:setState 需要一段时间来更新状态对象值(即)setState 不会立即更新状态对象,因为它本质上是异步的。
参考:Why React setState/useState does not update immediately - blog
下面列出了该问题可能的解决方案
案例A:根据'pressed'状态对象设置'result'状态对象
注意:使用回调函数设置目标对象状态更改后设置其他对象的状态
Objective:仅在设置 'pressed' 状态对象后设置 'result' 状态对象
实现:设置'pressed'状态后,我们执行一个回调函数来设置'result'状态对象
语法:
this.setState(setTargetStateObject, function() {
// 执行 setTargetStateObject 完成后必须完成的操作
});
解法:
buttonPressed(e) {
e.preventDefault();
const pressed = e.target.name;
this.setState({ pressed }, function() {
this.setState({ result: this.state.pressed });
});
}
案例 B:根据传递的 'e' arg 值设置结果状态对象
解法:
buttonPressed(e) {
e.preventDefault();
const pressed = e.target.name;
// const result = this.state.pressed;
// directly assign the 'e' arg value to the result const variable
const result = pressed;
// 'result' state object is not dependent on 'pressed' state object
this.setState({ pressed });
this.setState({ result });
console.log(e.target.name);
}
注意:我建议你使用功能组件因为你可以有一个干净的代码,行数更少,使用新的React 团队引入了钩子,更容易编写测试,最重要的是性能。
为您创建了这个沙箱 calculator pgm - class vs functional react component - 您可以查看您的相同程序是如何在 class 与功能组件中实现的。
参考文献:
对于这个问题的简单性,我很抱歉,我是 React 的新手。我构建了一个带有两个输入字段的计算器,然后是用于处理不同计算的按钮。现在,我正在把它改造成一个功能更齐全的全键盘计算器。在我下面的代码中,我很确定我编写“onClick”函数的方式是问题所在,但我不确定它应该如何编写。 (示例中的大部分代码都与初始项目有关,与此问题无关,我只是想包括整个组件以备不时之需。)
当我点击“1”按钮时,控制台第一次记录 1,但页面顶部的 1 直到第二次点击才显示。在我第二次单击“1”按钮之前,我在这里发生了什么,不允许显示在顶部?
第一次点击: App after first click on 1
第二次点击: App after second click on 1
class Calculator extends React.Component {
constructor(props) {
super(props);
this.setNum1 = this.setNum1.bind(this);
this.setNum2 = this.setNum2.bind(this);
this.add = this.add.bind(this);
this.subtract = this.subtract.bind(this);
this.multiply = this.multiply.bind(this);
this.divide = this.divide.bind(this);
this.clear = this.clear.bind(this);
this.buttonPressed = this.buttonPressed.bind(this);
this.state = {
pressed: "",
result: "",
num1: "",
num2: "",
};
}
buttonPressed(e) {
e.preventDefault();
const pressed = e.target.name;
const result = this.state.pressed;
this.setState({ pressed });
this.setState({ result });
console.log(e.target.name);
}
setNum1(e) {
const num1 = e.target.value ? parseInt(e.target.value) : "";
this.setState({ num1 });
}
setNum2(e) {
const num2 = e.target.value ? parseInt(e.target.value) : "";
this.setState({ num2 });
}
add(e) {
e.preventDefault();
const result = this.state.num1 + this.state.num2;
this.setState({ result });
}
subtract(e) {
e.preventDefault();
const result = this.state.num1 - this.state.num2;
this.setState({ result });
}
multiply(e) {
e.preventDefault();
const result = this.state.num1 * this.state.num2;
this.setState({ result });
}
divide(e) {
e.preventDefault();
const result = this.state.num1 / this.state.num2;
this.setState({ result });
}
clear(e) {
e.preventDefault();
this.setState({ num1: "", num2: "", result: 0 });
}
render() {
const { num1, num2, result } = this.state;
return (
<div>
<h1>{this.state.result}</h1>
<input onChange={this.setNum1} value={num1}></input>
<input onChange={this.setNum2} value={num2}></input>
<br />
<button name="1" onClick={this.buttonPressed}>
1
</button>
<button onClick={this.add}>+</button>
<button onClick={this.subtract}>-</button>
<button onClick={this.multiply}>x</button>
<button onClick={this.divide}>/</button>
<button onClick={this.clear}>clear</button>
</div>
);
}
}
export default Calculator;
如果有人能帮助我了解我需要做些什么来解决这种情况,我将不胜感激!
这里的问题在
buttonPressed(e) {
e.preventDefault();
// here e.target.name is 1 so value in const pressed becomes 1
const pressed = e.target.name;
// currently this.state.pressed is "" so result becomes "" if you want to show
// first number as result use const result = e.target.name
const result = this.state.pressed;
this.setState({ pressed });
this.setState({ result });
console.log(e.target.name);
}
您将结果设置为 this.state.pressed,第一次为空,因此将结果设置为空字符串,但第二次 this.state.pressed 为 1,因此将结果设置为 1,因此它第二次点击显示
推理:
阻止导致问题
buttonPressed(e) { e.preventDefault(); const pressed = e.target.name; const result = this.state.pressed; this.setState({ pressed }); this.setState({ result }); console.log(e.target.name); }
原因:setState 需要一段时间来更新状态对象值(即)setState 不会立即更新状态对象,因为它本质上是异步的。
参考:Why React setState/useState does not update immediately - blog
下面列出了该问题可能的解决方案
案例A:根据'pressed'状态对象设置'result'状态对象
注意:使用回调函数设置目标对象状态更改后设置其他对象的状态
Objective:仅在设置 'pressed' 状态对象后设置 'result' 状态对象
实现:设置'pressed'状态后,我们执行一个回调函数来设置'result'状态对象
语法:
this.setState(setTargetStateObject, function() { // 执行 setTargetStateObject 完成后必须完成的操作 });
解法:
buttonPressed(e) { e.preventDefault(); const pressed = e.target.name; this.setState({ pressed }, function() { this.setState({ result: this.state.pressed }); }); }
案例 B:根据传递的 'e' arg 值设置结果状态对象
解法:
buttonPressed(e) { e.preventDefault(); const pressed = e.target.name; // const result = this.state.pressed; // directly assign the 'e' arg value to the result const variable const result = pressed; // 'result' state object is not dependent on 'pressed' state object this.setState({ pressed }); this.setState({ result }); console.log(e.target.name); }
注意:我建议你使用功能组件因为你可以有一个干净的代码,行数更少,使用新的React 团队引入了钩子,更容易编写测试,最重要的是性能。
为您创建了这个沙箱 calculator pgm - class vs functional react component - 您可以查看您的相同程序是如何在 class 与功能组件中实现的。
参考文献: