目前看最新官方文档,setState存在的位置已经在 过时的React API内部了,但是类组件还是有在存在使用的,
this.setState([partialState], [callback])
partialState:支持部分状态更改
this.setState({ x:100 //不论总共有多少状态,我们只修改了x,其余的状态不动 });
callback:在状态更改/视图更新完毕后触发执行「也可以说只要执行了setState,callback一定会执行」
- 发生在componentDidUpdate周期函数之后「DidUpdate会在任何状态更改后都触发执行;而回调函数方式,可以在指定状态更新后处理一些事情;」
- 特殊:即便我们基于shouldComponentUpdate阻止了状态/视图的更新,DidUpdate周期函数肯定不会执行了,但是我们设置的这个callback回调函数依然会被触发执行!!
- 类似于Vue框架中的$nextTick!!
setState是异步操作
在React18中,setState探作都是异步的「不论是在哪执行,例如:合成事件、周期函数、定时器。」
目的:
1.实现状态的批处理「统一处理」
2.有效减少更新次数,降低性能消耗
3.有效管理代码执行的逻辑顺序
原理:利用了更新队列 「updater」机制来处理的
- 在当前相同的时间段内「浏览器此时可以处理的事情中」,遇到setstate会立即放入到更新队列中!
- 此时状态/视图还未更新
- 当所有的代码操作结束,会“刷新队列”「通知更新队列中的任务执行」:把所有放入setState合井在一起执行,只触发一次视图更新「批处理操作」
从图上可以看到:
1.在事件内更新数据,可以看到是异步的更新
2.多个状态值更新时,render只会渲染一次
发现组件更新流程: shouleUpdate ---> willUpdate ----> 修改状态值 ---> render ----> didUpdate ----->callback(setState内的第二个参数)
在上图中,发现是先执行了其他打印内容,然后获取到callback内的值,就具体和下图的更新流程有关系了,callback在组件componentDidUpdate执行完成后才执行
获取更新后的值
setState的第二个参数callback会执行,在更新后执行拿到值
this.setState({
num: num+1,
count: count+1
}, () => {
console.log("num1", this.state.num) // 1
});
处理机制
异步操作【内容是视频截图】
内部有更新队列,setState设置的值,不会立即更新 会先添加到更新队列,然后进行批处理操作,数据处理完成后,运行更新操作
同步操作
当前上下文执行的时候不考虑异步操作,不会等待定时器
当前上下文执行过程中,同步代码至上而下执行完成后,把所有setState 放在更新队列当中,同步代码执行完成后,会通知队列执行setState运行
总结
React18中,对于setState的操作,采用了 批处理!
- 构建了队列机制
- 统一更新,提高视图更新的性能
- 处理流程更加稳健
在React 18之前,我们只在 React合成事件/周期函数期间批量更新;默认情况下,React中不会对 promise、setTimeout、原生事件处理(native event handlers)或其它React默认不进行批处理的事件进行批处理操作!
16/ 18版本对比
React 16
运行结果:
这里可以看到数据 z 在setTimeout内的数据由原来的 0 变为 1,内部的setState的数据即时更新
React 18
这里可以看到数据 z 在setTimeout内的数据没有任何变化,内部的setState的数据是异步操作
结论: 在React18 和 React16中,关于setState是同步还是异步,是有一些区别的!
React18中:不论在什么地方执行setState,它都是异步的「都是基于updater更新队列机制,实现的批处理」
React16中:如果在合成事件「jsx元素中基于onXxx绑定的事件」、周期函数中,setState的操作是异步的!!但是如果setState出现在其他异步操作中「例如:定时器、手动获取DOM元素做的事件绑定等」,它将变为同步的操作「立即更新状态和让视图渲染」!!
获取state更新前的值
上面的是通过callback获取更新后的值,现在是获取更新前的值 setState接收的参数还可以是一个函数,在这个函数中可以拿先前的状态,并通过这个函数的返回值得到下一个状态
this.setState((prevState)=>{
// prevState:存储之前的状态值
// return的对象,就是我们想要修改的新状态值「支持修改部分状态」
return {
xxx:xxx
};
})