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

React中的setState的同步异步与合并(2)

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

合并

然后我们来看一道题目:

代码语言:javascript
复制

function incrementMultiple() {
  this.setState({count: this.state.count + 1});
  this.setState({count: this.state.count + 1});
  this.setState({count: this.state.count + 1});
}

请问这个时候,this.state.count的值为多少呢?答案为1

浅析

数据的合并

代码语言:javascript
复制
Object.assign({}, prevState, partialState)
// 也就是说
  this.setState({Age: '22'})
  this.setState({Name: 'srtian'})
// 等价于
this.setState({Age: '22', Name: 'srtian})
代码语言:javascript
复制
this.state = {
    message: "Hello World",
    name: "wyx"
 }
this.setState({
     message: "你好啊,帅哥"
 });

通过setState去修改message,是不会对name产生影响的;

源码中其实是有对 原对象 和 新对象进行合并的:

setState本身的合并

this.setState会通过引发一次组件的更新过程来引发重新绘制。也就是说setState的调用会引起React的更新生命周期的四个函数的依次调用:

shouldComponentUpdate

componentWillUpdate

rende

componentDidUpdate

我们都知道,在React生命周期函数里,以render函数为界,无论是挂载过程和更新过程,在render之前的几个生命周期函数,this.state和Props都是不会发生更新的,直到render函数执行完毕后,this.state才会得到更新。(有一个例外:当shouldComponentUpdate函数返回false,这时候更新过程就被中断了,render函数也不会被调用了,这时候React不会放弃掉对this.state的更新的,所以虽然不调用render,依然会更新this.state。)

React的官方文档有提到过这么一句话:

状态更新会合并(也就是说多次setstate函数调用产生的效果会合并)。

看源码

代码语言:javascript
复制
ReactComponent.prototype.setState = function(partialState, callback) {
  invariant(
    typeof partialState === 'object' ||
      typeof partialState === 'function' ||
      partialState == null,
    'setState(...): takes an object of state variables to update or a ' +
      'function which returns an object of state variables.',
  );
  this.updater.enqueueSetState(this, partialState);
  if (callback) {
    this.updater.enqueueCallback(this, callback, 'setState');
  }
};
 enqueueSetState: function(publicInstance, partialState) {
    if (__DEV__) {
      ReactInstrumentation.debugTool.onSetState();
      warning(
        partialState != null,
        'setState(...): You passed an undefined or null state object; ' +
          'instead, use forceUpdate().',
      );
    }

    var internalInstance = getInternalInstanceReadyForUpdate(
      publicInstance,
      'setState',
    );

    if (!internalInstance) {
      return;
    }

    var queue =
      internalInstance._pendingStateQueue ||
      (internalInstance._pendingStateQueue = []);
    queue.push(partialState);

    enqueueUpdate(internalInstance);
  }
// 通过enqueueUpdate执行state更新
function enqueueUpdate(component) {
  ensureInjected();
  // batchingStrategy是批量更新策略,isBatchingUpdates表示是否处于批量更新过程
  // 最开始默认值为false
  if (!batchingStrategy.isBatchingUpdates) {
    batchingStrategy.batchedUpdates(enqueueUpdate, component);
    return;
  }
  dirtyComponents.push(component);

  if (component._updateBatchNumber == null) {
    component._updateBatchNumber = updateBatchNumber + 1;
  }
}
// 对_pendingElement, _pendingStateQueue, _pendingForceUpdate进行判断,
// _pendingStateQueue由于会对state进行修改,所以不为空,
// 然后会调用updateComponent方法
performUpdateIfNecessary: function(transaction) {
    if (this._pendingElement != null) {
      ReactReconciler.receiveComponent(
        this,
        this._pendingElement,
        transaction,
        this._context,
      );
    } else if (this._pendingStateQueue !== null || this._pendingForceUpdate) {
      this.updateComponent(
        transaction,
        this._currentElement,
        this._currentElement,
        this._context,
        this._context,
      );
    } else {
      this._updateBatchNumber = null;
    }
  },

其中这段代码需要额外注意:

代码语言:javascript
复制
  // batchingStrategy是批量更新策略,isBatchingUpdates表示是否处于批量更新过程
  // 最开始默认值为false
if (!batchingStrategy.isBatchingUpdates) {
    batchingStrategy.batchedUpdates(enqueueUpdate, component);
    return;
  }
dirtyComponents.push(component);
if (component._updateBatchNumber == null) {
    component._updateBatchNumber = updateBatchNumber + 1;
  }

上面这段代码的意思就是如果是处于批量更新模式,也就是isBatchingUpdates为true时,不进行state的更新操作,而是将需要更新的component添加到dirtyComponents数组中。

如果不处于批量更新模式,则对所有队列中的更新执行batchedUpdates方法。

然后可以找到了这个batchedUpdates:

代码语言:javascript
复制

var ReactDefaultBatchingStrategy = {
  // 也就是上面提到的默认为false
  isBatchingUpdates: false,
  // 这个方法只有在isBatchingUpdates: false时才会调用
  // 但一般来说,处于react大事务中时,会在render中的_renderNewRootComponent中将其设置为true。
  batchedUpdates: function(callback, a, b, c, d, e) {
    var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;
    ReactDefaultBatchingStrategy.isBatchingUpdates = true;
    // The code is written this way to avoid extra allocations
    if (alreadyBatchingUpdates) {
      return callback(a, b, c, d, e);
    } else {
      return transaction.perform(callback, null, a, b, c, d, e);
    }
  },

即:

当我们调用setState时,最终会通过enqueueUpdate执行state更新,就像上面那样有两种更新的模式,一种是批量更新模式,将组建保存在dirtyComponents;另一种非批量模式,将会遍历dirtyComponents,对每一个dirtyComponents调用updateComponent方法。

本文系转载,前往查看

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

本文系转载前往查看

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

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