返回博主主页

react——setState源码解析

源码在node_modules/react/.目录下

 

 1、node_modules/react/dist/react.js

定义了ReactComponent

function ReactComponent(props, context, updater) {
  this.props = props;
  this.context = context;
  this.refs = emptyObject;
  // We initialize the default updater but the real one gets injected by the
  // renderer.
  this.updater = updater || ReactNoopUpdateQueue;
}

定义了ReactComponent的prototype

ReactComponent.prototype.isReactComponent = {};

ReactComponent.prototype.setState = function (partialState, callback) {
  !(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null) ? "development" !== 'production' ? invariant(false, 'setState(...): takes an object of state variables to update or a ' + 'function which returns an object of state variables.') : invariant(false) : undefined;
  if ("development" !== 'production') {
    "development" !== 'production' ? warning(partialState != null, 'setState(...): You passed an undefined or null state object; ' + 'instead, use forceUpdate().') : undefined;
  }
  this.updater.enqueueSetState(this, partialState);
  if (callback) {
    this.updater.enqueueCallback(this, callback);
  }
};

ReactComponent.prototype.forceUpdate = function (callback) {
  this.updater.enqueueForceUpdate(this);
  if (callback) {
    this.updater.enqueueCallback(this, callback);
  }
};

updater的两处定义在node_modules/react/lib/ReactUpdateQueue.js和node_modules/react/lib/ReactNoopUpdateQueue.js

2、node_modules/react/lib/ReactNoopUpdateQueue.js

定义了ReactNoopUpdateQueue的空操作Noop:

  1 /**
  2  * Copyright 2015, Facebook, Inc.
  3  * All rights reserved.
  4  *
  5  * This source code is licensed under the BSD-style license found in the
  6  * LICENSE file in the root directory of this source tree. An additional grant
  7  * of patent rights can be found in the PATENTS file in the same directory.
  8  *
  9  * @providesModule ReactNoopUpdateQueue
 10  */
 11 
 12 'use strict';
 13 
 14 var warning = require('fbjs/lib/warning');
 15 
 16 function warnTDZ(publicInstance, callerName) {
 17   if (process.env.NODE_ENV !== 'production') {
 18     process.env.NODE_ENV !== 'production' ? warning(false, '%s(...): Can only update a mounted or mounting component. ' + 'This usually means you called %s() on an unmounted component. ' + 'This is a no-op. Please check the code for the %s component.', callerName, callerName, publicInstance.constructor && publicInstance.constructor.displayName || '') : undefined;
 19   }
 20 }
 21 
 22 /**
 23  * This is the abstract API for an update queue.
 24  */
 25 var ReactNoopUpdateQueue = {
 26 
 27   /**
 28    * Checks whether or not this composite component is mounted.
 29    * @param {ReactClass} publicInstance The instance we want to test.
 30    * @return {boolean} True if mounted, false otherwise.
 31    * @protected
 32    * @final
 33    */
 34   isMounted: function (publicInstance) {
 35     return false;
 36   },
 37 
 38   /**
 39    * Enqueue a callback that will be executed after all the pending updates
 40    * have processed.
 41    *
 42    * @param {ReactClass} publicInstance The instance to use as `this` context.
 43    * @param {?function} callback Called after state is updated.
 44    * @internal
 45    */
 46   enqueueCallback: function (publicInstance, callback) {},
 47 
 48   /**
 49    * Forces an update. This should only be invoked when it is known with
 50    * certainty that we are **not** in a DOM transaction.
 51    *
 52    * You may want to call this when you know that some deeper aspect of the
 53    * component's state has changed but `setState` was not called.
 54    *
 55    * This will not invoke `shouldComponentUpdate`, but it will invoke
 56    * `componentWillUpdate` and `componentDidUpdate`.
 57    *
 58    * @param {ReactClass} publicInstance The instance that should rerender.
 59    * @internal
 60    */
 61   enqueueForceUpdate: function (publicInstance) {
 62     warnTDZ(publicInstance, 'forceUpdate');
 63   },
 64 
 65   /**
 66    * Replaces all of the state. Always use this or `setState` to mutate state.
 67    * You should treat `this.state` as immutable.
 68    *
 69    * There is no guarantee that `this.state` will be immediately updated, so
 70    * accessing `this.state` after calling this method may return the old value.
 71    *
 72    * @param {ReactClass} publicInstance The instance that should rerender.
 73    * @param {object} completeState Next state.
 74    * @internal
 75    */
 76   enqueueReplaceState: function (publicInstance, completeState) {
 77     warnTDZ(publicInstance, 'replaceState');
 78   },
 79 
 80   /**
 81    * Sets a subset of the state. This only exists because _pendingState is
 82    * internal. This provides a merging strategy that is not available to deep
 83    * properties which is confusing. TODO: Expose pendingState or don't use it
 84    * during the merge.
 85    *
 86    * @param {ReactClass} publicInstance The instance that should rerender.
 87    * @param {object} partialState Next partial state to be merged with state.
 88    * @internal
 89    */
 90   enqueueSetState: function (publicInstance, partialState) {
 91     warnTDZ(publicInstance, 'setState');
 92   },
 93 
 94   /**
 95    * Sets a subset of the props.
 96    *
 97    * @param {ReactClass} publicInstance The instance that should rerender.
 98    * @param {object} partialProps Subset of the next props.
 99    * @internal
100    */
101   enqueueSetProps: function (publicInstance, partialProps) {
102     warnTDZ(publicInstance, 'setProps');
103   },
104 
105   /**
106    * Replaces all of the props.
107    *
108    * @param {ReactClass} publicInstance The instance that should rerender.
109    * @param {object} props New props.
110    * @internal
111    */
112   enqueueReplaceProps: function (publicInstance, props) {
113     warnTDZ(publicInstance, 'replaceProps');
114   }
115 
116 };
117 
118 module.exports = ReactNoopUpdateQueue;
View Code

 

主要看ReactUpdateQueue.js

3、node_modules/react/lib/ReactUpdateQueue.js

这儿主要分析enqueueCallback和enqueueSetState。

var ReactUpdateQueue = {

  /**
   * Enqueue a callback that will be executed after all the pending updates
   * have processed.
   *
   * @param {ReactClass} publicInstance The instance to use as `this` context.
   * @param {?function} callback Called after state is updated.
   * @internal
   */
  enqueueCallback: function (publicInstance, callback) {
    !(typeof callback === 'function') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'enqueueCallback(...): You called `setProps`, `replaceProps`, ' + '`setState`, `replaceState`, or `forceUpdate` with a callback that ' + 'isn\'t callable.') : invariant(false) : undefined;
    var internalInstance = getInternalInstanceReadyForUpdate(publicInstance);

    // Previously we would throw an error if we didn't have an internal
    // instance. Since we want to make it a no-op instead, we mirror the same
    // behavior we have in other enqueue* methods.
    // We also need to ignore callbacks in componentWillMount. See
    // enqueueUpdates.
    if (!internalInstance) {
      return null;
    }

    if (internalInstance._pendingCallbacks) {
      internalInstance._pendingCallbacks.push(callback);
    } else {
      internalInstance._pendingCallbacks = [callback];
    }
    // TODO: The callback here is ignored when setState is called from
    // componentWillMount. Either fix it or disallow doing so completely in
    // favor of getInitialState. Alternatively, we can disallow
    // componentWillMount during server-side rendering.
    enqueueUpdate(internalInstance);
  },
}

 

posted @ 2022-02-18 14:36  懒惰的星期六  阅读(262)  评论(0编辑  收藏  举报

Welcome to here

主页