简体   繁体   English

为什么在重新呈现setstate之后执行绑定事件

[英]Why the binding event is executed after the setstate is re-rendered

The Test component has a state of num , the component implements the function of clicking the button num+1, the button is bound to the self-increment method, the keyup is also bound to the method, the method uses the setState to re-render the value of num , but the effect of clicking the button with the mouse is not the same as the keyboard trigger event. Test组件的状态为num ,组件实现单击按钮num + 1的功能,按钮绑定到自增量方法, keyup也绑定到方法,该方法使用setState重新渲染num的值,但用鼠标单击按钮的效果与键盘触发事件不同。 Could you tell me why, please? 你能告诉我为什么吗?

When I click the button, console logs the num first, then done . 当我单击按钮时,控制台首先记录num ,然后done
But when I press enter, console logs done , then the num . 但是当我按下回车键,控制台日志done ,然后是num

React15.5 React15.5

class Test extends React.PureComponent {
    constructor(){
        super();
        this.state = {
            num : 1
        }
    }
    add = () => {
        const {num} = this.state;
        this.setState({num:num+1},()=>{
            console.log("done")
        })
        console.log(this.state.num)
    }

    componentDidMount() {
        document.body.addEventListener('keyup', this.add);
    }
    componentWillUnmount() {
        document.body.removeEventListener('keyup', this.add);
    }

    render() {
        return(
            <Button onClick={this.add} >add</Button>
            <span>{this.state.num}</span>
        )
    }
}

Using the setState method with an object as the first parameter will execute the method asynchronously as descibed here . 使用带有对象作为第一个参数的setState方法将像这里所描述的那样异步执行该方法。 Therefore the order of console logs in your code may differ every time. 因此,代码中控制台日志的顺序可能每次都不同。

The reason you see a difference between the click and keyboard events is because the click event is a React.SyntheticEvent and the keyboard event is a DOM event. 您看到单击和键盘事件之间的差异的原因是因为click事件是React.SyntheticEvent并且键盘事件是DOM事件。 It seems like handling the click event takes less time so your console.log(this.state.num) executes before React is done updating your state. 似乎处理click事件花费的时间更少,因此在React完成更新状态之前执行console.log(this.state.num)

If you want to see the same behaviour for both triggers I would suggest to use the componentDidUpdate lifecycle method. 如果你想看到两个触发器的相同行为,我建议使用componentDidUpdate生命周期方法。 This lifecycle method waits until the update is done. 此生命周期方法将一直等到更新完成。

Edit 编辑

You can make the add method async and then await the execution of the setState method. 您可以使add方法异步,然后等待setState方法的执行。 Resulting add method: 结果添加方法:

add = async () => {
    await this.setState(
      {
        num: state.num + 1
      },
      () => {
        console.log("done");
      }
    );
    console.log(this.state.num);
};

This will make sure the code after await this.setState always waits untill the state has updated. 这将确保await this.setState之后的代码始终等待,直到状态已更新。

I think @ids-van-der-zee's answer has some important points to consider. 我认为@ids-van-der-zee的答案有一些重要的考虑因素。 But I think the root cause for the difference in the console output is in this answer: https://stackoverflow.com/a/33613918/4114178 但我认为控制台输出差异的根本原因在于以下答案: https//stackoverflow.com/a/33613918/4114178

React batches state updates that occur in event handlers and lifecycle methods ... To be clear, this only works in React-controlled synthetic event handlers React批处理事件处理程序和生命周期方法中发生的状态更新...要清楚,这仅适用于React控制的合成事件处理程序

I don't want to quote the entire answer, please read it, but in your case <Button onClick={this.add}... is a "React-controlled synthetic event handlers" where document.body.addEventListener('keyup', this.add); 我不想引用整个答案,请阅读它,但在你的情况下<Button onClick={this.add}... 一个“React-controlled synthetic event handlers”,其中document.body.addEventListener('keyup', this.add); adds an event listener which is not part of the React infrastructure. 添加一个属于React基础结构的事件监听器。 So the Button onClick setState call is batched until the render completes (and your callback is not called until the batch is executed, where the keyup setState call is not batched and happens immediately--before the console.log(num) statement). 因此,按钮onClick setState调用将被批处理直到渲染完成(并且在执行批处理之前不会调用回调,其中keyup setState调用未进行批处理并立即发生 - 在console.log(num)语句之前)。

I don't think in your case this is of any consequence, but I think it shows great attention to detail that you noticed. 我不认为在你的情况下这有任何后果,但我认为它显示出你注意到的细节。 There are cases where it become important, but I don't think you will hit them in this component. 有些情况下它成为重要的情况下,但我不认为你会打他们在此组件。 I hope this helps! 我希望这有帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM