前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >揭密 React setState

揭密 React setState

作者头像
用户1097444
发布2022-06-29 16:02:29
3230
发布2022-06-29 16:02:29
举报
文章被收录于专栏:腾讯IMWeb前端团队

本文由 IMWeb 团队成员 Daisy黄琼 首发于社区网站 imweb.io。点击阅读原文查看 IMWeb 社区更多精彩文章。

前言

学过react的人都知道,setState在react里是一个很重要的方法,使用它可以更新我们数据的状态,本篇文章从简单使用深入到setState的内部,全方位为你揭开setState的神秘面纱~

setState的使用注意事项

setState(updater,callback)这个方法是用来告诉react组件数据有更新,有可能需要重新渲染。它是异步的,react通常会集齐一批需要更新的组件,然后一次性更新来保证渲染的性能,所以这就给我们埋了一个坑:

那就是在使用 setState改变状态之后,立刻通过 this.state去拿最新的状态往往是拿不到的。

要点一

所以第一个使用要点就是:如果你需要基于最新的state做业务的话,可以在 componentDidUpdate或者 setState的回调函数里获取。(注:官方推荐第一种做法)

代码语言:javascript
复制
// setState回调函数changeTitle: function (event) {  this.setState({ title: event.target.value }, () => this.APICallFunction());},APICallFunction: function () {  // Call API with the updated value}
要点二

设想有一个需求,需要在在onClick里累加两次,如下

代码语言:javascript
复制
  onClick = () => {    this.setState({ index: this.state.index + 1 });    this.setState({ index: this.state.index + 1 });  }

在react眼中,这个方法最终会变成

代码语言:javascript
复制
Object.assign(  previousState,  {index: state.index+ 1},  {index: state.index+ 1},  ...)

由于后面的数据会覆盖前面的更改,所以最终只加了一次.所以如果是下一个state依赖前一个state的话,推荐给setState传function

代码语言:javascript
复制
onClick = () => {    this.setState((prevState, props) => {      return {quantity: prevState.quantity + 1};    });    this.setState((prevState, props) => {      return {quantity: prevState.quantity + 1};    });}

以上是使用setState的两个注意事项,接下来我们来看看setState被调用之后,更新组件的过程,下面是一个简单的流程图。

下面来逐步的解析图里的流程。

一、setState

ReactBaseClassses.js
代码语言:javascript
复制
ReactComponent.prototype.setState = function (partialState, callback) {  //  将setState事务放进队列中  this.updater.enqueueSetState(this, partialState);  if (callback) {    this.updater.enqueueCallback(this, callback, 'setState');  }};

这里的partialState可以传object,也可以传function,它会产生新的state以一种 Object.assgine()的方式跟旧的state进行合并。

二、enqueueSetState

代码语言:javascript
复制
  enqueueSetState: function (publicInstance, partialState) {     // 获取当前组件的instance    var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState');     // 将要更新的state放入一个数组里     var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);    queue.push(partialState);     //  将要更新的component instance也放在一个队列里    enqueueUpdate(internalInstance);  }

这段代码可以得知,enqueueSetState 做了两件事: 1、将新的state放进数组里 2、用enqueueUpdate来处理将要更新的实例对象

三、enqueueUpdate

ReactUpdates.js
代码语言:javascript
复制
function enqueueUpdate(component) {  // 如果没有处于批量创建/更新组件的阶段,则处理update state事务  if (!batchingStrategy.isBatchingUpdates) {    batchingStrategy.batchedUpdates(enqueueUpdate, component);    return;  }  // 如果正处于批量创建/更新组件的过程,将当前的组件放在dirtyComponents数组中  dirtyComponents.push(component);}

由这段代码可以看到,当前如果正处于创建/更新组件的过程,就不会立刻去更新组件,而是先把当前的组件放在dirtyComponent里,所以不是每一次的setState都会更新组件~。

这段代码就解释了我们常常听说的:setState是一个异步的过程,它会集齐一批需要更新的组件然后一起更新

而batchingStrategy 又是个什么东西呢?

四、batchingStrategy

ReactDefaultBatchingStrategy.js
代码语言:javascript
复制
var ReactDefaultBatchingStrategy = {  // 用于标记当前是否出于批量更新  isBatchingUpdates: false,  // 当调用这个方法时,正式开始批量更新  batchedUpdates: function (callback, a, b, c, d, e) {    var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;    ReactDefaultBatchingStrategy.isBatchingUpdates = true;    // 如果当前事务正在更新过程在中,则调用callback,既enqueueUpdate    if (alreadyBatchingUpdates) {      return callback(a, b, c, d, e);    } else {    // 否则执行更新事务      return transaction.perform(callback, null, a, b, c, d, e);    }  }};

这里注意两点: 1、如果当前事务正在更新过程中,则使用 enqueueUpdate将当前组件放在 dirtyComponent里。 2、如果当前不在更新过程的话,则执行更新事务。

五、transaction

代码语言:javascript
复制

简单说明一下transaction对象,它暴露了一个perform的方法,用来执行anyMethod,在anyMethod执行的前,需要先执行所有wrapper的initialize方法,在执行完后,要执行所有wrapper的close方法,就辣么简单。

在ReactDefaultBatchingStrategy.js,tranction 的 wrapper有两个 FLUSH_BATCHED_UPDATES,RESET_BATCHED_UPDATES

代码语言:javascript
复制
var RESET_BATCHED_UPDATES = {  initialize: emptyFunction,  close: function () {    ReactDefaultBatchingStrategy.isBatchingUpdates = false;  }};var FLUSH_BATCHED_UPDATES = {  initialize: emptyFunction,  close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates)};var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES];

可以看到,这两个wrapper的 initialize都没有做什么事情,但是在callback执行完之后,RESETBATCHEDUPDATES 的作用是将isBatchingUpdates置为false, FLUSHBATCHEDUPDATES 的作用是执行flushBatchedUpdates,然后里面会循环所有dirtyComponent,调用updateComponent来执行所有的生命周期方法,componentWillReceiveProps, shouldComponentUpdate, componentWillUpdate, render, componentDidUpdate 最后实现组件的更新。

以上即为setState的实现过程,最后还是用一个流程图在做一个总结吧~

参考文档:

  1. https://zhuanlan.zhihu.com/p/25882602
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-09-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯IMWeb前端团队 微信公众号,前往查看

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

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
    • setState的使用注意事项
      • 要点一
      • 要点二
    • 一、setState
      • ReactBaseClassses.js
    • 二、enqueueSetState
      • 三、enqueueUpdate
        • ReactUpdates.js
      • 四、batchingStrategy
        • ReactDefaultBatchingStrategy.js
      • 五、transaction
      相关产品与服务
      批量计算
      批量计算(BatchCompute,Batch)是为有大数据计算业务的企业、科研单位等提供高性价比且易用的计算服务。批量计算 Batch 可以根据用户提供的批处理规模,智能地管理作业和调动其所需的最佳资源。有了 Batch 的帮助,您可以将精力集中在如何分析和处理数据结果上。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档