关于React高频面试题:setState是同步还是异步?,笔者相信大部分react技术栈求职者都被问到过,本文主要总结一下笔者对于这个问题的一点理解,希望能给各位同学解决一丝困惑,不足之处请各位大佬多多指正。
笔者习惯通过代码的运行结果来总结结论和规律,世间万物都有其规律,本文也会结合一些demo来总结关于这个问题的答案。这样也是最有说服力的,废话不多说,上酸菜(错了错了...是上代码)
// demo1
class App extends React.Component {
state = {
num: 0
};
componentDidMount() {
this.setState({
num: this.state.num + 1
});
this.setState({
num: this.state.num + 2
});
console.log(this.state.num);
}
render() {
const { num } = this.state;
return <div>{ num }</div>;
}
}
ReactDOM.render(<App />, document.getElementById('root'));
// 控制台打印0,界面显示2
通过显示结果,我们可以得出结论一:在生命周期的函数场景下,setState是异步的,相同的状态属性多次更新会合并成一次,且最后一次会生效保留
// demo2
class App extends React.Component {
state = {
num: 0
};
handleClick = () => {
this.setState({
num: this.state.num + 1
});
this.setState({
num: this.state.num + 2
});
console.log(this.state.num); // 点击num控制台打印0,界面显示2
};
render() {
const { num } = this.state;
return <div onClick={this.handleClick}>{ num }</div>;
}
}
ReactDOM.render(<App />, document.getElementById('root'));
我们给div注册了一个click事件,界面渲染完之后,num显示是0,点击num显示2,控制台打印0,由于显示结果一样,笔者就没有配图,大家可以自行测试。通过该结果我们可以得出结论二:在React合成事件的场景下,setState是异步,关于React合成事件的概念,笔者会在文章最后解答,大佬可以去阅读React源码。(在这里onClick事件并不是JS原生事件,而是React合成事件)
// demo3
class App extends React.Component {
state = {
num: 0
};
componentDidMount() {
setTimeout(() => {
this.setState({
num: this.state.num + 1
});
this.setState({
num: this.state.num + 2
});
console.log(this.state.num); // 控制台打印3
}, 1000);
}
render() {
const { num } = this.state;
return <div>{ num }</div>;
}
}
ReactDOM.render(<App />, document.getElementById('root'));
React合成事件的机制:React并不是将click事件直接绑定在dom上面,而是采用事件冒泡的形式冒泡到document上面,然后React将事件封装给正式的函数处理运行。
如果DOM上绑定了过多的事件处理函数,整个页面响应以及内存占用可能都会受到影响。React为了避免这类DOM事件滥用,同时屏蔽底层不同浏览器之间的事件系统差异,实现了一个中间层——SyntheticEvent。
当用户在为onClick添加函数时,React并没有将Click事件绑定在DOM上面。而是在document处监听所有支持的事件,当事件发生并冒泡至document处时,React将事件内容封装交给中间层SyntheticEvent(负责所有事件合成)所以当事件触发的时候,会使用统一的分发函数dispatchEvent将指定函数执行。
总结:1,在生命周期函数,React合成事件场景下是异步:相同的状态属性(不同的状态属性不会影响)多次更新会合并成一次,最后一次会保留。 2,在定时器、原生DOM事件场景下是同步:会依次更新