51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

为什么 react 的 setState 要设计成异步的

在使用 React 的类组件时候我们常常会使用 setState 来更新状态,那么 setState 到底是同步的还是异步的呢?

|-----------------|------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 | changeMessage() { this.setState({message: "你好哇, 安知鱼"}) console.log(this.state.message); // hello world } |

这段代码最终打印结果是 hello world,可见 setState 是异步的操作,我们并不能在执行完 setState 之后立马拿到最新的 state 的结果,那么 setState 一定是异步的吗?

实践 {#实践}

那么 setState 一定是异步的吗?实际上在 React18 之前分为两种情况

  1. 在组件生命周期或者 React合成事件中,setState 是异步的。
  2. 在 setTimeout 或者原生 dom 事件中(promise 之类的),setState 是同步的。

React18 之前的同步情况

|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 | changeMessage() { setTimeout(() => { this.setState({message: "你好哇, 安知鱼"}) console.log(this.state.message); // 你好哇, 安知鱼 }, 0); } |

但是在 React18 之后默认所有的操作都被放到了批处理中(异步处理),即使你像上面那样操作依旧会是异步更新。

如果想要实现同步更新状态并 render 需要使用 flushSync 方法

|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 | import { flushSync } from "react-dom"; changeMessage() { flushSync(() => { this.setState({message: "你好哇, 安知鱼"}) }); console.log(this.state.message); // 你好哇, 安知鱼 } |

另外依旧可以传入第二个参数 callback 来获取更新完的状态。

探索 {#探索}

setState 设计为异步其实在 Github 上也有很多相关讨论:RFClarification: why is setState asynchronous?

其中 React 的核心成员(Redux 作者)Dan Abramov 也有对应的回复。

思考 {#思考}

总的看下来以后大概可以总结为以下几点

setState 设计为异步,可以显著的提升性能

如果每次调用 setState 都进行一次更新,那么意味着 render 函数会被频繁调用,界面重新渲染,这样效率是很低的。

最好的办法应该是获取到多个更新之后进行批量更新。

如果同步更新了 state,但是还没有执行 render 函数,那么 state 和 props 不能保持同步

state 和 props 不能保持一致性,会在开发中产生很多的问题。所以 React 采用了异步更新,并在 React18 中完全控制。

赞(1)
未经允许不得转载:工具盒子 » 为什么 react 的 setState 要设计成异步的