Test组件的状态为num
,该组件实现单击num + 1按钮的功能,该按钮绑定到自增量方法,keyup
也绑定到该方法,该方法使用setState
重新呈现num
的值,但是用鼠标单击按钮的效果与键盘触发事件不同。你能告诉我为什么吗?
当我单击按钮时,控制台首先记录num
,然后记录done
。
但是当我按Enter键时,控制台会先记录done
,然后记录num
。
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>
)
}
}
答案 0 :(得分:1)
将setState
方法与对象作为第一个参数一起使用,将按照here的方式异步执行该方法。因此,每次代码中控制台日志的顺序可能会有所不同。
您看到click事件和键盘事件之间存在差异的原因是,click事件是React.SyntheticEvent
,而键盘事件是DOM事件。似乎处理click事件花费的时间更少,因此您的console.log(this.state.num)
在React完成更新状态之前执行。
如果您想在两个触发器上看到相同的行为,我建议使用componentDidUpdate
生命周期方法。此生命周期方法将等待更新完成。
修改
您可以使add方法异步,然后等待setState
方法的执行。产生的添加方法:
add = async () => {
await this.setState(
{
num: state.num + 1
},
() => {
console.log("done");
}
);
console.log(this.state.num);
};
这将确保await this.setState
之后的代码始终等待状态更新。
答案 1 :(得分:1)
我认为@ ids-van-der-zee的答案需要考虑一些重要点。但是我认为导致控制台输出差异的根本原因是此答案:https://stackoverflow.com/a/33613918/4114178
反应批次状态更新发生在事件处理程序和生命周期方法中...要清楚,这仅在React控制的合成事件处理程序中起作用
我不想引用整个答案,请仔细阅读,但对于您而言,<Button onClick={this.add}...
是“反应控制的综合事件处理程序”,其中document.body.addEventListener('keyup', this.add);
添加一个事件监听器,它不是React基础架构的一部分。因此,Button onClick setState调用将一直进行批处理,直到渲染完成为止(在执行批处理之前,不会调用您的回调,而keyup setState调用不会进行批处理并立即发生在console.log(num)
语句之前)。>
我认为这对您没有任何影响,但是我认为它非常关注您注意到的细节。在某些情况下它变得很重要,但我认为您不会在本部分中找到它们。我希望这会有所帮助!