ReactUpdates source code (to be determined)

The ReactUpdates module stipulates the front and rear hooks of the component repainting process, including the front and rear hooks of the ReactReconcileTransaction module (you can add a componentDidUpdate callback, and provide updater parameters to the component to make the setState and other methods available), and the front and rear hooks set by the ReactUpdatesFlushTransaction function of this module (can be Add the callback callback after component repainting is completed); provide the interface of the ReactReconcileTransaction module through ReactUpdates.ReactReconcileTransaction; call the ReactDefaultBatchingStrategy module through ReactUpdates.enqueueUpdate to add dirty components or trigger repainting; Execute the fn function through ReactUpdates.batchedUpdates(fn), and trigger a repaint etc.

 

'use strict';

var _prodInvariant = require('./reactProdInvariant'),// Production environment React form with url error
    _assign = require('object-assign');
 
// An instance of a constructor that prototypically inherits Transaction will have the perform(method, args) method  
// The implementation function is that before and after the method function is executed, the paired pre-hook initialize and post-hook close are called; initialize provides parameters for close  
var CallbackQueue = require('./CallbackQueue');

// PooledClass.addPoolingTo(CopyConstructor) is used to convert the constructor CopyConstructor into a factory function  
// The meaning is to manage the creation and destruction of instance data, and push the instance of the destroyed data into the instance pool CopyConstructor.instancePool
var PooledClass = require('./PooledClass');

var ReactFeatureFlags = require('./ReactFeatureFlags');
var ReactReconciler = require('./ReactReconciler');

// An instance of a constructor that prototypically inherits Transaction will have the perform(method, args) method  
// The implementation function is that before and after the method function is executed, the paired pre-hook initialize and post-hook close are called; initialize provides parameters for close  
var Transaction = require('./Transaction');
 
// invariant(condition,format,a,b,c,d,e,f) condition is negative, replace "%s" in format, and throw error   
var invariant = require('fbjs/lib/invariant');

var dirtyComponents = [];
var updateBatchNumber = 0;
var asapCallbackQueue = CallbackQueue.getPooled();
var asapEnqueued = false;

var batchingStrategy = null;

// Confirm that ReactUpdates.ReactReconcileTransaction, batchingStrategy have been added
function ensureInjected() {
  !(ReactUpdates.ReactReconcileTransaction && batchingStrategy) ?
    process.env.NODE_ENV !== 'production' ?
      invariant(false, 'ReactUpdates: must inject a reconcile transaction class and batching strategy')
    : _prodInvariant ('123'): void 0;
}

// component update pre-hook, set this.dirtyComponentsLength to the number of dirty components in dirtyComponents
// Component update post hook, add dirty components during redraw, call flushBatchedUpdates to redraw the newly added dirty components
// No dirty components are added during the redraw process, and dirtyComponents are cleared
var NESTED_UPDATES = {
  initialize: function () {
    this.dirtyComponentsLength = dirtyComponents.length;
  },
  close: function () {
    // During the component redrawing process, add dirty components again, remove the redrawn components in dirtyComponents, and call flushBatchedUpdates to redraw the newly added dirty components
    if (this.dirtyComponentsLength !== dirtyComponents.length) {
      dirtyComponents.splice(0, this.dirtyComponentsLength);
      flushBatchedUpdates();
    } else {
      dirtyComponents.length = 0;
    }
  }
};

// Through the CallbackQueue callback function queue mechanism, that is, this.callbackQueue  
// Execute this.callbackQueue.enqueue(fn) to inject the callback callback after the component update is completed, and implement it in the runBatchedUpdates function
// Add pre and post hook mechanism through Transaction  
// The front hook initialize method is used to clear the callback queue; close is used to trigger the callback after the component update is completed
var UPDATE_QUEUEING = {
  initialize: function () {
    this.callbackQueue.reset();
  },
  close: function () {
    this.callbackQueue.notifyAll();
  }
};

var TRANSACTION_WRAPPERS = [NESTED_UPDATES, UPDATE_QUEUEING];

// Redraw each component in dirtyComponents with a specific hook, clear dirtyComponents, or call flushBatchedUpdates to redraw newly added dirty components
// Hooks include the hooks before and after ReactUpdatesFlushTransaction, which can add callbacks after component repainting _pendingCallbacks
// Including the hooks before and after ReactReconcileTransaction, you can add componentDidMount, componentDidUpdate callbacks
function ReactUpdatesFlushTransaction () {
  this.reinitializeTransaction();// Clear the front and back hooks through the Transaction module

  // The number of dirty components, used to update the dirty components to be redrawn in dirtyComponents
  this.dirtyComponentsLength = null;

  // this.callbackQueue is used to store the callback after the component update is completed
  this.callbackQueue = CallbackQueue.getPooled();

  // ReactReconcileTransaction instance
  this.reconcileTransaction = ReactUpdates.ReactReconcileTransaction.getPooled(/* useCreateElement */true);
}

_assign(ReactUpdatesFlushTransaction.prototype, Transaction, {
  // Set the pre and post hooks through the Transaction module, in the form of [{initialize,close}]  
  getTransactionWrappers: function () {
    return TRANSACTION_WRAPPERS;
  },

  // Clear the callback functions componentDidMount and componentDidUpdate in the ReactReconcileTransaction instance
  // Clear the callback function in the CallbackQueue, and then destroy this.reconcileTransaction
  destructor: function () {
    this.dirtyComponentsLength = null;
    CallbackQueue.release(this.callbackQueue);
    this.callbackQueue = null;
    ReactUpdates.ReactReconcileTransaction.release(this.reconcileTransaction);
    this.reconcileTransaction = null;
  },

  // Indirectly call the perform method of the ReactReconcileTransaction instance to execute the method, which is the runBatchedUpdates function of the current module
  // Before and after the method is executed, both the hook set by ReactReconcileTransaction and the hook set by ReactUpdatesFlushTransaction will be called
  perform: function (method, scope, a) {// a为ReactReconcileTransaction实例
    return Transaction.perform.call(this, this.reconcileTransaction.perform, this.reconcileTransaction, method, scope, a);
  }
});

// Manage instance creation through the PooledClass module ReactUpdatesFlushTransaction.getPooled
// and destruction of instance data ReactUpdatesFlushTransaction.release
PooledClass.addPoolingTo(ReactUpdatesFlushTransaction);

// When ReactDefaultBatchingStrategy.isBatchingUpdates is negative
// Execute the callback callback and call flushBatchedUpdates to redraw the dirty components in dirtyComponents
// batchingStrategy.isBatchingUpdates is true, only callback callback is executed
function batchedUpdates(callback, a, b, c, d, e) {
  ensureInjected();
  return batchingStrategy.batchedUpdates(callback, a, b, c, d, e);
}

// Compare the mount order of components
function mountOrderComparator(c1, c2) {
  return c1._mountOrder - c2._mountOrder;
}

// Call performUpdateIfNecessary of each component in dirtyComponents to redraw the component
// Add the callback _pendingCallbacks of the component update completion to the ReactUpdatesFlushTransaction post hook
function runBatchedUpdates(transaction) {
  var len = transaction.dirtyComponentsLength;

  // In ReactUpdatesFlushTransaction, the front hook has assigned transaction.dirtyComponentsLength to dirtyComponents.length
  // Check again to make sure
  !(len === dirtyComponents.length) ?
    process.env.NODE_ENV !== 'production' ?
      invariant(false,
        'Expected flush transaction\'s stored dirty-components length (%s) '
        + 'to match dirty-components array length (%s).', len, dirtyComponents.length)
      : _prodInvariant('124', len, dirtyComponents.length)
      : void 0;

  // Sort by component mount order
  dirtyComponents.sort(mountOrderComparator);

  // Verify that component._updateBatchNumber of the component instance is equal to updateBatchNumber, only one component can be updated at a time
  // The meaning is that redrawing the component flushBatchedUpdates can only be done through the ReactUpdates.enqueueUpdate method
  // That is, the ReactDefaultBatchingStrategy.batchedUpdates method to redraw? ? ?
  updateBatchNumber++;

  for (var i = 0; i <len; i ++) {
    // If the component has not been mounted, make sure the component's performUpdateIfNecessary and _pendingCallbacks are empty
    var component = dirtyComponents[i];

    var callbacks = component._pendingCallbacks;
    component._pendingCallbacks = null;

    was markerName;
    if (ReactFeatureFlags.logTopLevelRenders) {
      var namedComponent = component;
      // Duck type TopLevelWrapper. This is probably always true.
      if (component._currentElement.type.isReactTopLevelWrapper) {
        namedComponent = component._renderedComponent;
      }
      markerName = 'React update: ' + namedComponent.getName();
      console.time(markerName);
    }

    // ReactReconciler.performUpdateIfNecessary indirectly calls component.performUpdateIfNecessary to redraw the component
    // transaction.reconcileTransaction即ReactReconcileTransaction实例
    // Used to provide updater parameters to components to make methods such as setState available; and to mount componentDidMount, componentDidUpdate callbacks
    ReactReconciler.performUpdateIfNecessary(component, transaction.reconcileTransaction, updateBatchNumber);

    if (markerName) {
      console.timeEnd(markerName);
    }

    // Add the callbacks callback function that needs to be triggered to execute after the component update is completed to the ReactUpdatesFlushTransaction post hook
    if (callbacks) {
      for (var j = 0; j < callbacks.length; j++) {
        transaction.callbackQueue.enqueue(callbacks[j], component.getPublicInstance());
      }
    }
  }
}

// Redraw each component in dirtyComponents with a specific hook
// Hooks include the hooks before and after ReactUpdatesFlushTransaction, including the callback _pendingCallbacks after the component is redrawn
// Including the hooks before and after ReactReconcileTransaction, including componentDidMount, componentDidUpdate callbacks
var flushBatchedUpdates = function () {
  while (dirtyComponents.length || asapEnqueued) {
    if (dirtyComponents.length) {
      // Get an instance of ReactUpdatesFlushTransaction
      var transaction = ReactUpdatesFlushTransaction.getPooled ();

      // Execute runBatchedUpdates
      // The runBatchedUpdates function calls the performUpdateIfNecessary of each component in dirtyComponents to redraw the component
      // Add the callback _pendingCallbacks of the component update completion to the ReactUpdatesFlushTransaction post hook
      // And execute the hooks before and after ReactUpdatesFlushTransaction, including the callback _pendingCallbacks after the component is redrawn
      // And execute the hooks before and after ReactReconcileTransaction, including componentDidMount, componentDidUpdate callbacks
      transaction.perform(runBatchedUpdates, null, transaction);

      // runBatchedUpdates and hook functions are executed, destroy ReactUpdatesFlushTransaction instance data
      ReactUpdatesFlushTransaction.release(transaction);
    }

    // When ReactDefaultBatchingStrategy.batchedUpdates triggers a redraw, execute the callback added by the asap method
    if (asapEnqueued) {
      asapEnqueued = false;
      var queue = asapCallbackQueue;
      asapCallbackQueue = CallbackQueue.getPooled();
      queue.notifyAll();
      CallbackQueue.release(queue);
    }
  }
};

// batchingStrategy.isBatchingUpdates is when ReactDefaultBatchingStrategy.isBatchingUpdates is negative
// Means batchingStrategy.batchedUpdates is not executing, add dirty components and call flushBatchedUpdates to redraw
// batchingStrategy.isBatchingUpdates is true, only add dirty components to dirtyComponents
function enqueueUpdate(component) {
  ensureInjected();

  // batchingStrategy.isBatchingUpdates is true during the execution of batchingStrategy.batchedUpdates, and the execution is complete.
  // Set a specific hook implementation through the Transition module, and also include a hook to call flushBatchedUpdates to redraw dirty components
  if (!batchingStrategy.isBatchingUpdates) {
    batchingStrategy.batchedUpdates(enqueueUpdate, component);
    return;
  }

  dirtyComponents.push(component);
  if (component._updateBatchNumber == null) {
    component._updateBatchNumber = updateBatchNumber + 1;
  }
}

// Mount the callback callback, which is valid when the ReactDefaultBatchingStrategy.batchedUpdates redraw mechanism is triggered
// That is, the callback function used to mount ReactDefaultBatchingStrategy.batchedUpdates method redraw
function asap(callback, context) {
  // batchingStrategy.isBatchingUpdates is when ReactDefaultBatchingStrategy.isBatchingUpdates is negative
  // ReactDefaultBatchingStrategy.batchedUpdates redrawing mechanism is not triggered, an error is reported
  !batchingStrategy.isBatchingUpdates ?
    process.env.NODE_ENV !== 'production' ?
    invariant (false, 'ReactUpdates.asap:'
      + 'Can\'t enqueue an asap callback in a context whereupdates are not being batched.')
    : _prodInvariant ('125'): void 0;

  asapCallbackQueue.enqueue(callback, context);
  asapEnqueued = true;
}

// Configure different injectors according to the development environment
// Among them, ReactUpdates.ReactReconcileTransaction is used to agree on hook functions before and after component mounting, and add componentDidMount and componentDidUpdate callbacks
// and pass the updater parameter to the component constructor to make the setState, replaceState, forceUpdate methods available
// What is batchingStrategy for? ? ?
var ReactUpdatesInjection = {
  // In the ReactDefaultInjection module, set ReactUpdates.ReactReconcileTransaction to the ReactReconcileTransaction module
  injectReconcileTransaction: function (ReconcileTransaction) {
    !ReconcileTransaction ? process.env.NODE_ENV !== 'production' ?
      invariant(false, 'ReactUpdates: must provide a reconcile transaction class')
      : _prodInvariant ('126'): void 0;

    ReactUpdates.ReactReconcileTransaction = ReconcileTransaction;
  },

  // In the ReactDefaultInjection module, set the batchingStrategy to the ReactDefaultBatchingStrategy module
  injectBatchingStrategy: function (_batchingStrategy) {
    !_batchingStrategy ? process.env.NODE_ENV !== 'production' ?
      invariant(false, 'ReactUpdates: must provide a batching strategy')
      : _prodInvariant ('127'): void 0;

    !(typeof _batchingStrategy.batchedUpdates === 'function') ?
      process.env.NODE_ENV !== 'production' ?
        invariant(false, 'ReactUpdates: must provide a batchedUpdates() function')
      : _prodInvariant ('128'): void 0;

    !(typeof _batchingStrategy.isBatchingUpdates === 'boolean') ?
      process.env.NODE_ENV !== 'production' ?
        invariant(false, 'ReactUpdates: must provide an isBatchingUpdates boolean attribute')
        : _prodInvariant ('129'): void 0;

    batchingStrategy = _batchingStrategy;
  }
};

var ReactUpdates = {
  // Default is ReactReconcileTransaction module
  // The implementation function is to call the specified hook function in the mountComponentIntoNode function, including the user-configured componentDidMount and componentDidUpdate callbacks
  // Use the method to create an instance for the getPooled method, and the release method to destroy the instance data
  // The perform method executes the mountComponentIntoNode function, and the front and rear hook functions
  // getReactMountReady().enqueue(fn) adds user-configured componentDidMount and componentDidUpdate callbacks
  // getReactMountReady().checkpoint() method to get the number of callbacks
  // getReactMountReady().rollback(checkpoint) sets the number of callbacks to checkpoint
  // Another implementation function is to inject the updater parameter into the component instance, which will provide functional functions to the setState, replaceState, and forceUpdate methods
  ReactReconcileTransaction: null,

  // When ReactDefaultBatchingStrategy.isBatchingUpdates is negative
  // Execute the callback callback and call flushBatchedUpdates to redraw the dirty components in dirtyComponents
  // batchingStrategy.isBatchingUpdates is true, only callback callback is executed
  batchedUpdates: batchedUpdates,

  // batchingStrategy.isBatchingUpdates is when ReactDefaultBatchingStrategy.isBatchingUpdates is negative
  // Means batchingStrategy.batchedUpdates is not executing, add dirty components and call flushBatchedUpdates to redraw
  // batchingStrategy.isBatchingUpdates is true, only add dirty components to dirtyComponents
  enqueueUpdate: enqueueUpdate,
  
  // Redraw each component in dirtyComponents with a specific hook
  // Hooks include the hooks before and after ReactUpdatesFlushTransaction, including the callback _pendingCallbacks after the component is redrawn
  // Including the hooks before and after ReactReconcileTransaction, including componentDidMount, componentDidUpdate callbacks
  flushBatchedUpdates: flushBatchedUpdates,

  // Through the output interface of the ReactInjection module, the ReactDefaultInjection module adds the specified ReactReconcileTransaction and batchingStrategy
  // Among them, ReactUpdates.ReactReconcileTransaction defaults to the ReactReconcileTransaction module
  // batchingStrategy defaults to ReactDefaultBatchingStrategy module
  injection: ReactUpdatesInjection,

  // Used to mount the callback function when the ReactDefaultBatchingStrategy.batchedUpdates method redraws
  smoke: smoke
};

module.exports = ReactUpdates;

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326971414&siteId=291194637