setState执行的背后是什么 小灰灰 2022-05-21 13:13 154阅读 0赞 react-native技术交流微信群,定期会分享react native 技术文章,移动技术干货,精彩文章技术推送。欢迎各位大牛,React Native技术爱好者加入交流! ![20180104174639448][] 在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 做了什么?** ![70][] 图片来源: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的内容了,有问题的可以留言讨论。 [20180104174639448]: /images/20220521/cef7f22c2de747999909e2561ba85e74.png [70]: /images/20220521/7e5df6d947404b6fb430600908013f56.png
还没有评论,来说两句吧...