React setState的同步与异步

setState的同步和异步

首先我们要知道为什么React中要使用setState来修改数据,简单来说原因包括如下几点:

  • 因为我们修改了state之后,希望React根据最新的State来重新渲染界面,但是这种方式的修改React并不知道数据发生了变化
  • React并没有实现类似于Vue2中的Object.defineProperty或者Vue3中的Proxy的方式来监听数据的变化
  • 我们必须通过setState来告知React数据己经发生了变化

setState有如下几个写法:

(1). setState(stateChange, [callback])------对象式的setState
        1.stateChange为状态改变对象(该对象可以体现出状态的更改)
        2.callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用
                
(2). setState(updater, [callback])------函数式的setState
        1.updater为返回stateChange对象的函数。
        2.updater可以接收到之前的state和props。
        4.callback是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用。
        总结:
  1.对象式的setState是函数式的setState的简写方式(语法糖)
    2.使用原则:
                (1).如果新状态不依赖于原状态 ===> 使用对象方式
                (2).如果新状态依赖于原状态 ===> 使用函数方式
                (3).如果需要在setState()执行后获取最新的状态数据, 
                    要在第二个callback函数中读取

setState的更新是异步的?其实分成两种情况:

  • 在组件生命周期或React合成事件中,setstate是异步

  • setTimeout或者原生dom事件中,setstate是同步

    而在React18之后,默认所有的操作都放到了批处理(异步处理)中了,详见官网博客:React v18.0 – React Blog (reactjs.org)

如果我们想要进行更新之后立刻就可以使用修改之后的值应该怎么操作呢?这里我们可以从ReactDOM中取出并使用flushSync方法,它相当于实现了一次同步的更新,这样我们setState之后立刻拿到修改之后的值。

截屏2022-10-26 22.06.02

  • 那为什么setState设计为异步呢?

    • setstate设计为异步其实之前在GitHub上也有很多的讨论;

    • React核心成员(Redux的作者)Dan Abramov也有对应的回复,可以参考Dan的回答:RFClarification: why is setState asynchronous? · Issue #11527 · facebook/react (github.com)

    • 可以简单总结为以下观点:

      • setState设计为异步,可以显著的提升性能
        • 如果每次调用 setState都进行一次更新,那么意味着render函数会被频繁调用,界面重新渲染,这样效率是很低的
        • 最好的办法应该是获取多个更新,之后批量进行更新
        • 如果同步更新了state,但是还没有执行render函数,那么state和props不能保持同步
          • state和props不能保持一致性,会在开发中产生很多的问题

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!