为什么我必须点击两次才能触发事件?

时间:2020-07-13 21:45:22

标签: javascript reactjs onclick event-handling

很抱歉,这个问题的简单性,我对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;

如果有人能帮助我了解解决这种情况的必要措施,我将非常感激!

2 个答案:

答案 0 :(得分:2)

问题出在这里

 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,因此在第二次点击

答案 1 :(得分:0)

原因:

  • 导致问题的阻止

    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:基于“按下”状态对象设置“结果”状态对象

  • 注意:一旦使用回调函数设置了目标对象状态更改,就可以设置其他对象的状态

  • 目标:仅在设置了“按下”状态对象后才设置“结果”状态对象

  • 实现:一旦设置了“按下”状态,我们将执行一个回调函数来设置“结果”状态对象

  • 语法:

    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-您可以查看如何在类或功能组件中实现相同的程序。

参考: