react中setState的同步/异步问题
- react中setState并不是单纯的同步或异步,关于同步和异步的判断,取决于调用时所处的环境
- 在合成事件和生命周期钩子中(除
componentDidUpdate以外),setState是异步的
- 原则:如果当前有事务流正在执行,则组件的更新无法进行,而是会被推入
dirtyComponents队列中等待事务流结束之后执行;如果当前没有事务流,则组件的更新会被直接推入到batchedUpdates队列中执行
- 原因:
- 在生命周期钩子函数调用中,更新策略都处于更新操作之前,此时组件仍然处于事务流之中,所以无法同步更新状态;但是,
componentDidUpdate钩子是在更新之后,此时组件已经不在事务流之中了,所以是同步的setState
- 在合成事件中,react事务流是基于事件委托完成的,所以事务流是处于一个正在执行的状态,相关的
setState是异步的
- 异步setState存在的问题是:无法立刻获取到最新的state
- 解决办法:在setState中使用第二个参数,也就是添加回调函数:
setState((newState), callback(){return newState})
- 在原生事件和
setTimeout中,setState的实现是同步的:可以马上获取到更新后的状态
- 原因:原生事件是浏览器本身的实现,与事务流无关,所以是同步事件。setTimeout是在定时器线程中执行的,此时事务流已经结束,所以也是同步的
- 批量更新: 在合成事件以及除了
componentDidMount的生命周期钩子中,setState更新状态时,存储的是合并状态,也就意味着之前存入的key值会被之后的覆盖,最终只执行一次渲染更新
- 函数式setState:
- 由于Fiber以及合并的问题,react官方推荐使用函数式
setState(fn),fn返回新state,也就是setState((state,props)=>newState)
- 使用函数式setState可以避免setState批量更新的逻辑,减少计算量