⚡ 30 秒速记
- 状态调用提交更新,不返回提交完成承诺
- 批处理边界与版本影响更新可见时机
- 当前函数闭包仍保留本轮快照
- 基于前值计算用函数更新
- 强制同步是特殊工具,不是日常修补方式
问状态更新同步还是异步,最好拆成调用、计算和提交三个时机。 更新函数可以立即返回,但页面和下一轮状态未必立刻完成;同一回调里的变量也仍是当前渲染快照。批处理随根节点模式和版本变化,不能拿旧定时器案例套所有环境。依赖前一个状态时提交计算函数,想观察更新结果则选择对应的提交后机制,而不是给状态调用加 await。
版本校准: 原理文章中的代码代表特定实现与写作时间。应用到当前项目时,应先确认浏览器、框架或工具的主版本,再区分稳定的规范语义、可变化的内部实现和项目自身约束。
# 从一道面试题说起
这是一道变体繁多的面试题,在 BAT 等一线大厂的面试中考察频率非常高。首先题目会给出一个这样的 App 组件,在它的内部会有如下代码所示的几个不同的 setState 操作:
import React from "react";
import "./styles.css";
export default class App extends React.Component{
state = {
count: 0
}
increment = () => {
console.log('increment setState前的count', this.state.count)
this.setState({
count: this.state.count + 1
});
console.log('increment setState后的count', this.state.count)
}
triple = () => {
console.log('triple setState前的count', this.state.count)
this.setState({
count: this.state.count + 1
});
this.setState({
count: this.state.count + 1
});
this.setState({
count: this.state.count + 1
});
console.log('triple setState后的count', this.state.count)
}
reduce = () => {
setTimeout(() => {
console.log('reduce setState前的count', this.state.count)
this.setState({
count: this.state.count - 1
});
console.log('reduce setState后的count', this.state.count)
},0);
}
render(){
return <div>
<button onClick={this.increment}>点我增加</button>
<button onClick={this.triple}>点我增加三倍</button>
<button onClick={this.reduce}>点我减少</button>
</div>
}
}