前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React中的setState的同步异步与合并

React中的setState的同步异步与合并

作者头像
Qwe7
发布2022-06-09 08:31:31
9500
发布2022-06-09 08:31:31
举报
文章被收录于专栏:网络收集

前言

这篇文章主要是因为自己在学习React中setState的时候,产生了一些疑惑,所以进行了一定量的收集资料和学习,并在此记录下来

引入

使用过React的应该都知道,在React中,一个组件中要读取当前状态需要访问this.state,但是更新状态却需要使用this.setState,不是直接在this.state上修改,就比如这样:

代码语言:javascript
复制

//读取状态
const count = this.state.count;

//更新状态
this.setState({count: count + 1});

//无意义的修改
this.state.count = count + 1;

同步和异步

开发中我们并不能直接通过修改state的值来让界面发生更新:

因为我们修改了state之后,希望React根据最新的State来重新渲染界面,但是这种方式的修改React并不知道数据发生了变化;

React并没有实现类似于Vue2中的Object.defineProperty或者Vue3中的Proxy的方式来监听数据的变化;

我们必须通过setState来告知React数据已经发生了变化;

疑惑:在组件中并没有实现setState的方法,为什么可以调用呢?

原因很简单,setState方法是从Component中继承过来的

(1)setState异步更新

setState的更新是异步的?

代码语言:javascript
复制
changeText() {
  this.setState({
     message: "你好啊,李银河"
   })
   console.log(this.state.message); // Hello World
}

最终打印结果是Hello World;

可见setState是异步的操作,我们并不能在执行完setState之后立马拿到最新的state的结果

为什么setState设计为异步呢?

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

React核心成员(Redux的作者)Dan Abramov也有对应的回复,有兴趣的同学可以参考一下;

https://github.com/facebook/react/issues/11527#issuecomment-360199710;

我对其回答做一个简单的总结:

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

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

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

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

state和props不能保持一致性,会在开发中产生很多的问题;

(2)如何获取异步的结果

那么如何可以获取到更新后的值呢?

方式一:setState的回调

setState接受两个参数:第二个参数是一个回调函数,这个回调函数会在更新后会执行;

格式如下:setState(partialState, callback)

代码语言:javascript
复制

this.setState({
    message: "你好啊,李银河"
}, () => {
    console.log(this.state.message);
})

方式二:在生命周期函数内获取

代码语言:javascript
复制
componentDidUpdate() {
    // 方式二: 获取异步更新的state
    console.log(this.state.message);
}

(3)setState一定是异步吗?

其实分成两种情况:

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

在setTimeout或者原生dom事件中,setState是同步;

验证一:在setTimeout中的更新:

代码语言:javascript
复制
changeText() {
// 情况一: 将setState放入到定时器中
    setTimeout(() => {
        this.setState({
        message: "你好啊,李银河"
    })
    console.log(this.state.message); // 你好啊,李银河
    }, 0);
}

验证二:原生DOM事件:

代码语言:javascript
复制
componentDidMount() {
 document.getElementById("btn").addEventListener("click", (e) => {
    this.setState({
      message: "你好啊,李银河"
    })
    console.log(this.state.message);
  })

  // this.setState({
  //   message: "你好啊,李银河"
  // })
  // console.log(this.state.message);
}

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档