最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 加加 React 30 问 -- 1. setState 是同步还是异步

    正文概述 掘金(厨猿加加)   2021-03-01   726

    1. setState 是同步还是异步

    要想回答这个问题,首先先看例子,

    import React, { Component } from 'react'
    import './App.css';
    
    class ClsApp extends Component {
        state = {
            num: 0
        }
        updateNum = () => {
            console.log('setState 前',this.state.num)
            this.setState({ num: this.state.num + 1 })
            console.log('setState 后 -- 正常',this.state)
    
            // setTimeout(() => {
            //     this.setState({ num: this.state.num + 1 })
            //     console.log('setState 后 -- setTimeout',this.state)
            // })
        }
    
        render() {
            return (
                <>
                    <button onClick={this.updateNum}>+1</button>
                    <p>{this.state.num}</p>
                </>
            )
        }
    }
    
    export default ClsApp
    
    

    在这个例子中,正常点击触发更新,this.state 的值前后一致,我们说它是异步的,而如果放在 setTimeout 中,前后不一致,我们说它是同步的,那么到底是怎么肥事呢?

    考虑 setState 是同步还是异步是没有意义的

    • 回到上面这个例子,无论是同步还是异步,我们都能在视图中得到我们想要的更新过后的结果,而当我们需要做一些依赖更新过后的值的操作,本身就不应该编写在 setState 之后。
    • 如果我们想要依赖更新之后的状态值
      • 在 ClassComponent 中,我们可以在 componentDidMounted 或者 componentDidUpdate 中执行
      • 在 FunctionComponent 中,我们可以在 useEffect 的回调函数中执行
    • 在业务中一旦需要考虑这个特性,大概率都是写法出问题了,推荐按照正规的写法重新编码,而不是在纠结它的同步异步特性。

    React 在不同 mode 下,对 setState 触发的更新有不同的处理

    legacy模式 -- ReactDOM.render

    • 默认情况下使用 useSate 的是异步的,原因是 React 内部有一个性能优化机制 -- batchedUpdates 批处理
      • 这个性能优化机制是为了多次调用 setState 触发更新的时候,合并成一个更新,减少因状态更新引擎的页面渲染过多而导致的性能问题。
      • 在 react 的声明周期函数中调用 setState,会执行 batchedUpdates,这个时候会首先加入一个 batchedContext 的标志,有这个标志就会使得 setState 的 action 放入到 batchedUpdateQueue 中
      • 因此,调用 setState 之后,不会立刻执行更新,而是要将(1-n个) useState 的 action 放在 batchedUpdateQueue 队列中的。等到 react 上下文结束了,又会取消 batched 标志,这个时候就同步执行响应的回调了。
    • 当我们用 setTimeout 包裹 setState 的时候,当执行的时候,不会走 react 内部的 batchedUpdates 优化机制, 此时运行上下文为 noContext;在调度更新过程中,如果是同步优先级 + noContext 上下文,就会执行同步执行回调队列 flushSyncCallbackQueue.
    • 因此在 legacy 模式下,如果是在可以触发 react 机制的位置上使用 setState, 是异步执行的,如果是 setTimeout 这种不会触发 react 机制的上下包裹下使用 setState,是同步的。

    Concurrent 模式下 -- 暂时还属于试验阶段, ReactDOM.unstable_createRoot().render()

    • 在 legacy 中,使用 setTimeout 包裹 setState 会是同步执行的,原因是 legacy 模式下,FiberRoot 对应的 lane 是 Synclane 同步优先级
      • 在同步优先级的时候,如果上下文是 noContext,才会同步执行
    • 而在 Concurrent 模式下,是异步优先级,所以所有的更新都是异步的
    • 因此无论怎么处理,使用 setState 触发的更新都是异步的。

    小结

    • Legacy 模式下,命中 batchUpdates 时是异步的,未命中时是同步的
    • 在 Concurrent 模式下都是异步的

    参考

    • 可以参考 WorkLoop 源码文件中的 scheduleUpdateOnFiber 函数进行进一步的学习
    • 卡颂老师关于 setState 问题的视频

    起源地下载网 » 加加 React 30 问 -- 1. setState 是同步还是异步

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元