美文网首页前端开发那些事儿
React 中 setState 是同步的还是异步的的?

React 中 setState 是同步的还是异步的的?

作者: 弱冠而不立 | 来源:发表于2021-03-28 16:10 被阅读0次

    首先说结论,不同模式下有不同的结果
    在 React 的官网,在有关 Concurrnt 模式下这一章的介绍中能看到,当前 React 为了平滑的迁移到 Fiber 架构,推出了三个模式进行过渡。

    • legacy 模式: ReactDOM.render(<App />, rootNode)。这是当前 React app 使用的方式。当前没有计划删除本模式,但是这个模式可能不支持这些新功能。
    • blocking 模式: ReactDOM.createBlockingRoot(rootNode).render(<App />)。目前正在实验中。作为迁移到 concurrent 模式的第一个步骤。
    • concurrent 模式: ReactDOM.createRoot(rootNode).render(<App />)。目前在实验中,未来稳定之后,打算作为 React 的默认开发模式。这个模式开启了所有的新功能。

    传统(legacy)模式下

    结论
    • React 事件调用 this.setState() 是异步的
    • 摆脱 React 的执行上下文,跳出批量更新的操作,可以使用 setTimeout 这种异步事件包裹 this.setState,就可以跳出React的执行上下文环境,这样就是同步的。

    可以查看这个示例看一下:codesandbox示例

    原因

    React 有个性能优化的特性:批量更新(batchedUpdates)
    简单描述一下场景就是,当你在一个React事件里触发多次 setState 执行状态的更新操作,那么只有最后一次的 setState 能被真正的更新到。
    简单概括一下就是,React将一个事件里的多次 setState 合并为一次更新。

    那为什么使用 setTimeout 包裹就可以使得 setState 变成同步更新的呢?
    首先明白JS的事件执行机制,同步任务和异步任务是两个不同的机制。同步函数执行时,压入函数执行栈;异步任务进入事件队列。

    • 当在 React 的函数中调用 setState,会被识别到当前的上下文执行环境有一次可以优化的批量更新操作,进而去对这些处于同一个函数执行上下文的 setState 去批量更新。
    • 而当使用 setTimeout 使得 setState 并没有压入函数上下文执行栈,而是进入事件队列了,然后此时React对于这些脱离自己控制的 setState 都是进行同步更新没有做额外的优化

    Concurrent 模式下

    结论

    无论什么情况下,setState 都是异步的(都是批量更新的)
    在线Demo查看:react版本选择的是实验性的版本

    在源码中,legacy 模式下更新的优先级是同步的,而 concurrent 模式下更新的优先级是异步的(详情可以看:React 实验阶段的 Concurrent 模式)。从而在源码中走的条件判断不一样。

    简要概括就是:传统模式下 React 需要先判断当前的函数执行上下文有没有 setState ,有的话然后再进行批量更新。而 Concurrent 模式下,只要是 setState 都是批量更新的。

    相关文章

      网友评论

        本文标题:React 中 setState 是同步的还是异步的的?

        本文链接:https://www.haomeiwen.com/subject/gizvaktx.html