React-setState的那些事儿

关于setState,使用过react的人应该再熟悉不过了,在hooks还不那么普及的时候,除了使用函数式组件,我们使用最多的应该就是类创建react的组件了,而在类组件中我们通常会使用state来管理组件的数据变化及更新。

setState的使用注意事项

setState(updater, callback)这个方法是用来告诉react组件数据更新渲染。

在使用setState改变状态之后,立刻通过this.state去拿最新的状态往往可能并不容易拿到的。

 

要点1:

基于此如果需要拿到最新的state,根据官方给的方法就是在‘componentDidUpdate或者在setState的第二个参数的回调函数中获取

componentDidMount(){
    this.setState({
      date: 3,
    }, function(){
      console.log('callback',this.state.date) // date为 3
    });
    console.log('fn',this.state.date) // date为1
  }

 

要点2:

对于同时累加多次的问题

componentDidMount(){
    this.setState({
      date: this.state.date + 1,
    });
    this.setState({
      date: this.state.date + 1,
    });
    this.setState({
      date: this.state.date + 1,
    });
  }
// 最后date的值只累加了一次,为2

我们的目标值可能是4,但是react最后给出的与我们目标值不一样,这是因为react为了考虑性能问题,防止重复渲染将setState方法统一在渲染前统一进行,之后再进行render

如果想要得到4,推荐再setState传function

componentDidMount(){
    this.setState((state) => {
      return {date: state.date + 1}
    });
    this.setState((state) => {
      return {date: state.date + 1}
    });
    this.setState((state) => {
      return {date: state.date + 1}
    });
  }

// 最后得到目标值4

 

那么setState是同步的还是异步的?

从上面我们发现当我们在setState后没法立即拿到我们设置的值,可能很多人想说,因为setState是异步的。情况真的是这样吗,看下面的例子

// 定时器中
componentDidMount(){
    setTimeout(() => {
      this.setState({
        date: 2
      });
      console.log('1111', this.state.date) // date为2
    })
  }

// 或者监听函数
componentDidMount(){
    document.getElementById('button').addEventListener('click', this.clicks)
  }
  
clicks = () => {
    this.setState({
      date:3,
    })
    console.log('addEventListener', this.state.date); // date为3
  }

我们发现在在定时器或者是监听函数等原生方法中时,当我们设置setState,我们是可以同步的拿到最新的state的值得。

而根据react源码,和我个人的理解setState是其实用同步的操作来模仿的异步的行为。

我们知道react为了兼容各种浏览器,同时为了性能的考量有自己的合成事件,譬如onClick、onChang之类的。当我们在生命周期中或者合成事件中,setState将变成异步的行为,而在js原生事件中setState将变成同步的。

那react是如何区分的呢,其实可以简单的理解为,react对于异步的setState会给方法打上一个isBatchingUpdates,并将它放在一个处理state的队列中,当react其他任务执行完需要开始渲染前,将循环处理队列中的方法,同时更新state

而对于同步的setState则进行直接更新。

 

参考👏😬


https://github.com/facebook/react/issues/11527

https://github.com/olifer655/react/issues/12

posted on 2021-06-06 17:18  smallpen  阅读(89)  评论(0编辑  收藏  举报