美文网首页react
setState分析

setState分析

作者: 你的时间非常值钱 | 来源:发表于2019-07-25 23:43 被阅读0次

    组件更新方法

    1.setState
    2.replaceState(后面废弃)
    3.forceUpdate

    setState
    ReactComponent.prototype.setState = function(particalState, callback) {
      this.updater.enqueueSetState(this, particalState);
      if (callback) {
       this.updater.enqueueCallback(this, callback, 'setState');
      }
    };
    

    enqueueSetState

      enqueueSetState: function(publicInstance, partialState) {
        ...
    
        var internalInstance = getInternalInstanceReadyForUpdate(
          publicInstance,
          'setState'
        );
    
        if (!internalInstance) {
          return;
        }
    
        var queue =
          internalInstance._pendingStateQueue ||
          (internalInstance._pendingStateQueue = []);
        queue.push(partialState);
    
        enqueueUpdate(internalInstance);
      },
    

    enqueueCallback

    enqueueCallback: function(publicInstance, callback, callerName) {
        ReactUpdateQueue.validateCallback(callback, callerName);
        var internalInstance = getInternalInstanceReadyForUpdate(publicInstance);
    
        ...
        if (!internalInstance) {
          return null;
        }
    
        if (internalInstance._pendingCallbacks) {
          internalInstance._pendingCallbacks.push(callback);
        } else {
          internalInstance._pendingCallbacks = [callback];
        }
        ...
        enqueueUpdate(internalInstance);
      },
    

    两个方法共同点:
    1.getInternalInstanceReadyForUpdate,获取ReactCompositeComponentWrapper实例
    2.enqueueSetState将新state推入_pendingStateQueue队列,enqueueCallback将callback推进_pendingCallbacks队列
    3.最后都调用enqueueUpdate方法


    enqueueUpdate

    function enqueueUpdate(internalInstance) {
      ReactUpdates.enqueueUpdate(internalInstance);
    }
    ...
    function enqueueUpdate(component) {
      ensureInjected();
    
      ...
    
      if (!batchingStrategy.isBatchingUpdates) {
        batchingStrategy.batchedUpdates(enqueueUpdate, component);
        return;
      }
    
      dirtyComponents.push(component);
      if (component._updateBatchNumber == null) {
        component._updateBatchNumber = updateBatchNumber + 1;
      }
    }
    

    isBatchingUpdates决定了是否处于事务中,是就将component推入dirtyComponent,不是就将自己(enqueueUpdate)放入事务执行


    function ensureInjected() {
      invariant(
        ReactUpdates.ReactReconcileTransaction && batchingStrategy,
        'ReactUpdates: must inject a reconcile transaction class and batching ' +
        'strategy'
      );
    }
    

    在ensureInjected里看到, ReactUpdates依赖了ReactUpdates.ReactReconcileTransactionbatchingStrategy
    ReactReconcileTransaction:处理生命周期相关更新工作
    batchingStrategy:处理批量更新

    React中的事务

    /**
     * <pre>
     *                       wrappers (injected at creation time)
     *                                      +        +
     *                                      |        |
     *                    +-----------------|--------|--------------+
     *                    |                 v        |              |
     *                    |      +---------------+   |              |
     *                    |   +--|    wrapper1   |---|----+         |
     *                    |   |  +---------------+   v    |         |
     *                    |   |          +-------------+  |         |
     *                    |   |     +----|   wrapper2  |--------+   |
     *                    |   |     |    +-------------+  |     |   |
     *                    |   |     |                     |     |   |
     *                    |   v     v                     v     v   | 
     *                    | +---+ +---+   +---------+   +---+ +---+ | 
     * perform(anyMethod) | |   | |   |   |         |   |   | |   | | 
     * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
     *                    | |   | |   |   |         |   |   | |   | |
     *                    | |   | |   |   |         |   |   | |   | |
     *                    | |   | |   |   |         |   |   | |   | |
     *                    | +---+ +---+   +---------+   +---+ +---+ |
     *                    |  initialize                    close    |
     *                    +-----------------------------------------+
     * </pre>
     */
    
    // 事务结束时将isBatchingUpdates 设为false
    var RESET_BATCHED_UPDATES = {
      initialize: emptyFunction,
      close: function() {
        ReactDefaultBatchingStrategy.isBatchingUpdates = false;
      },
    };
    
    // 事务结束时执行flushBatchedUpdates,在事务的close阶段运行runBatchedUpdates来update,close,执行顺序是FLUSH_BATCHED_UPDATES到RESET_BATCHED_UPDATES 
    var FLUSH_BATCHED_UPDATES = {
      initialize: emptyFunction,
      close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates),
    };
    
    // wrapper组合
    var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES];
    
    function ReactDefaultBatchingStrategyTransaction() {
      this.reinitializeTransaction(); // 在Mixin的里的初始化方法
    }
    
    Object.assign(
      ReactDefaultBatchingStrategyTransaction.prototype,
      Transaction.Mixin, // 包括initializeAll,closeAll,perform等逻辑
      {
        getTransactionWrappers: function() {
          return TRANSACTION_WRAPPERS;
        },
      }
    );
    
    var transaction = new ReactDefaultBatchingStrategyTransaction();
    
    流程.png

    flushBatchedUpdates

    var flushBatchedUpdates = function() {
      ...
      while (dirtyComponents.length || asapEnqueued) {
        if (dirtyComponents.length) {
          var transaction = ReactUpdatesFlushTransaction.getPooled();
          transaction.perform(runBatchedUpdates, null, transaction);
          ReactUpdatesFlushTransaction.release(transaction);
        }
    
        if (asapEnqueued) {
          asapEnqueued = false;
          var queue = asapCallbackQueue;
          asapCallbackQueue = CallbackQueue.getPooled();
          queue.notifyAll();
          CallbackQueue.release(queue);
        }
      }
      ...
    };
    

    runBatchedUpdates

    function runBatchedUpdates(transaction) {
      var len = transaction.dirtyComponentsLength;
      ...
    
      dirtyComponents.sort(mountOrderComparator);
      updateBatchNumber++;
    
      for (var i = 0; i < len; i++) {
        var component = dirtyComponents[i];
        var callbacks = component._pendingCallbacks;
        component._pendingCallbacks = null;
        ...
    
        ReactReconciler.performUpdateIfNecessary(
          component,
          transaction.reconcileTransaction,
          updateBatchNumber
        );
        ...
    
      }
    }
    

    遍历所有dirtyComponents,通过mountOrderComparator排序,将callback放入事务队列

     performUpdateIfNecessary: function(
        internalInstance,
        transaction,
        updateBatchNumber
      ) {
        ...
        internalInstance.performUpdateIfNecessary(transaction);
        ...
      },
    

    发现调用的是internalInstance的方法,它属于ReactCompositeComponentWrapper,在ReactCompositeComponent里找

    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;
        }
      },
    

    判断如果element级别的比较不同就会调用receiveComponent,_pendingStateQueue 和_pendingForceUpdate情况下,调用updateComponent

    updateComponent

    updateComponent: function(
        transaction,
        prevParentElement,
        nextParentElement,
        prevUnmaskedContext,
        nextUnmaskedContext
      ) {
        var inst = this._instance;
        ...
    
        var willReceive = false;
        var nextContext;
        var nextProps;
    
        // context检查,如果变化存到nextContext
        if (this._context === nextUnmaskedContext) {
          nextContext = inst.context;
        } else {
          nextContext = this._processContext(nextUnmaskedContext);
          willReceive = true;
        }
    
        nextProps = nextParentElement.props;
    
        if (prevParentElement !== nextParentElement) {
          willReceive = true;
        }
    
        // 判断props更新,出发componentWillReceiveProps生命周期
        if (willReceive && inst.componentWillReceiveProps) {
          ...
          inst.componentWillReceiveProps(nextProps, nextContext);
          ...
        }
        
       // _processPendingState处理最新state
        var nextState = this._processPendingState(nextProps, nextContext);
        var shouldUpdate = true;
        //  是否执行生命周期shouldComponentUpdate
        if (!this._pendingForceUpdate && inst.shouldComponentUpdate) {
          ...
          shouldUpdate = inst.shouldComponentUpdate(nextProps, nextState, nextContext);
          ...
        }
    
        ...
    
        this._updateBatchNumber = null;
       // 是否更新虚拟DOM,是就通过_performComponentUpdate更新,否则只改变值
        if (shouldUpdate) {
          this._pendingForceUpdate = false;
          // 更新 `this.props`, `this.state` 和`this.context`.
          this._performComponentUpdate(
            nextParentElement,
            nextProps,
            nextState,
            nextContext,
            transaction,
            nextUnmaskedContext
          );
        } else {
          this._currentElement = nextParentElement;
          this._context = nextUnmaskedContext;
          inst.props = nextProps;
          inst.state = nextState;
          inst.context = nextContext;
        }
      },
    
    _processPendingState
      _processPendingState: function(props, context) {
        var inst = this._instance;
        var queue = this._pendingStateQueue;
        var replace = this._pendingReplaceState;
        this._pendingReplaceState = false;
        this._pendingStateQueue = null;
    
        if (!queue) {
          return inst.state;
        }
    
        if (replace && queue.length === 1) {
          return queue[0];
        }
    
        var nextState = assign({}, replace ? queue[0] : inst.state);
        for (var i = replace ? 1 : 0; i < queue.length; i++) {
          var partial = queue[i];
          assign(
            nextState,
            typeof partial === 'function' ?
              partial.call(inst, nextState, props, context) :
              partial
          );
        }
    
        return nextState;
      },
    

    setState第一个参数除了可以是对象,也可以是函数,通过函数入参可以得到最新state,props和context

    相关文章

      网友评论

        本文标题:setState分析

        本文链接:https://www.haomeiwen.com/subject/rwuqrctx.html