关于State,你想知道的。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013718120/article/details/80956063

react-native技术交流微信群,定期会分享react native 技术文章,移动技术干货,精彩文章技术推送。欢迎各位大牛,React Native技术爱好者加入交流!


在React Native 或 React 的日常开发中,与State的接触必不可少。当我们需要让界面重新渲染时,需要去刷新State(setState)的当前状态,促使组件重新render。setState是如何导致Component刷新的呢,理解内部的运行机制,同样会帮助我们解决一些奇怪的问题。

先来看一段代码:

 constructor() {
    super();
    this.state = {
      num: 0
    };
  }
  
  componentDidMount() {
    this.setState({val: this.state.num+ 1});
    console.log(this.state.num);    

    this.setState({val: this.state.num+ 1});
    console.log(this.state.num);    

    setTimeout(() => {
      this.setState({val: this.state.num+ 1});
      console.log(this.state.num);  

      this.setState({val: this.state.num+ 1});
      console.log(this.state.num);  
    }, 0);
  }

上面代码,在最终的输出为:0, 0, 2, 3。 如果结果并不和你想的一样,那么接下来的内容你肯定感兴趣。

在解析上面的结果之前,我们需要了解下setState刷新机制的核心流程。

setState 做了什么?


    图片来源:https://zhuanlan.zhihu.com/p/20328570?columnSlug=purerender

上图中,我们会发现setState的核心执行流程:

(1)当调用setState(newState)时,将刷新任务加入执行队列

(2)判断当前任务栈是否处于更新state阶段

(3)如果处于更新state阶段,则将新的state刷新任务“缓存”于dirtyComponents中

(4)不处于更新state阶段,则遍历并执行“缓存”的state任务,调用updateComponent ,render

以上粗略的将setState执行流程总结为4步。其中主要的核心为是否处于batch update阶段的处理。在源码中,batch update阶段的判断采用了“isBatchingUpdates ”来区分,当其为true时,则会把当前的state更新任务“缓存”在dirtyComponents。反之,会立刻执行更新刷新。

在理解isBatchingUpdates 状态如何改变之前,我们要说一个概念:Transaction

这里的Transaction和数据库中的事务不同。Transaction作为state刷新过程的一次事务,会在前后执行初始化和关闭的一系列操作。

看文章开始的例子,componentDidMount 和 setTimeout 两者处在不同的任务栈中,并且setTimeout不会受React任务栈的管理和约束。在整个Component组件执行时,从初始化到渲染完成的过程就处于一个 Transaction 中。在 componentDidMount 中调用 setState 时,isBatchingUpdates 已经被设为 true(在render中设置(调用栈里)),所以 setState 的结果并没有立即生效,而是被放进了 dirtyComponents 中。 因为render执行比componentDidMount早,所以在componentDidMount里的2个setState不能立即执行

setTimeout 的执行堆栈和react回调的堆栈是不一样,所以  isBatchingUpdates 标志位是 false,也就导致了新的 state 马上生效,没有走到 dirtyComponents 。在componentDidMount运行结束后,Transaction这个事件也会运行并且是运行结束。当Transaction运行结束时,触发把isBatchingUpdates重新设置为初始状态 false。所有当setTimeout中的setState执行时,isBatchingUpdates是false,就直接刷新。

因为setTimeout在Component主任务栈执行完Transaction之后才会执行,所以此时this.state.num已经是执行过this.setState({ num: this.state.num + 1 })了,所以在setTimeout中的第一句setState执行完成后num就会变为2,以此类推。

再看一种情况:

constructor() {
    super();
    this.state = {
      num: 0
    };
  }
  
  componentDidMount() {
    this.setState({val: this.state.num+ 1});
    console.log(this.state.num);    

    this.setState({val: this.state.num+ 1});
    console.log(this.state.num);    

    this.setState({ });
    this.state.num = 110; // 此时num的值为 100
    console.log(this.state.num);
  }

上述代码中,我们执行了 this.setState({ })。当执行该方法时,会将除其它setState里面排列的值之外的,其它的用this.state.xxx直接赋值的内容,重新render。

以上就是关于State的内容了,有问题的可以留言讨论。

猜你喜欢

转载自blog.csdn.net/u013718120/article/details/80956063