__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { // For TapEventPlugin which is popular in open source EventPluginHub: require('EventPluginHub'), // Used by test-utils EventPluginRegistry: require('EventPluginRegistry'), EventPropagators: require('EventPropagators'), ReactControlledComponent: require('ReactControlledComponent'), ReactDOMComponentTree, ReactDOMEventListener: require('ReactDOMEventListener'), ReactUpdates: ReactUpdates, }, };
var nextContext = getContextForSubtree(parentComponent); // 拿到当前的顶层容器组件 var prevComponent = getTopLevelWrapperInContainer(container); // 对于第一次 render 来说,prevComponent 为 null if (prevComponent) { var prevWrappedElement = prevComponent._currentElement; var prevElement = prevWrappedElement.props.child; if (shouldUpdateReactComponent(prevElement, nextElement)) { var publicInst = prevComponent._renderedComponent.getPublicInstance(); var updatedCallback = callback && function() { validateCallback(callback); callback.call(publicInst); }; ReactMount._updateRootComponent( prevComponent, nextWrappedElement, nextContext, container, updatedCallback, ); return publicInst; } else { ReactMount.unmountComponentAtNode(container); } }
var reactRootElement = getReactRootElementInContainer(container); var containerHasReactMarkup = reactRootElement && !!internalGetID(reactRootElement); var containerHasNonRootReactChild = hasNonRootReactChild(container);
// The initial render is synchronous but any updates that happen during // rendering, in componentWillMount or componentDidMount, will be batched // according to the current batching strategy. ReactUpdates.batchedUpdates( batchedMountComponentIntoNode, componentInstance, container, shouldReuseMarkup, context, );
var wrapperID = componentInstance._instance.rootID; instancesByReactRootID[wrapperID] = componentInstance;
return componentInstance; },
instantiateReactComponent
根据传入的参数来生成不同的 React Component, 核心代码:
if (node === null || node === false) { instance = ReactEmptyComponent.create(instantiateReactComponent); } elseif (typeof node === 'object') { var element = node; var type = element.type; if (typeof type !== 'function' && typeof type !== 'string') { ... }
// Special case string values if (typeof element.type === 'string') { instance = ReactHostComponent.createInternalComponent(element); } elseif (isInternalComponentType(element.type)) { // This is temporarily available for custom components that are not string // representations. I.e. ART. Once those are updated to use the string // representation, we can drop this code path. instance = new element.type(element);
// We renamed this. Allow the old name for compat. :( if (!instance.getHostNode) { instance.getHostNode = instance.getNativeNode; } } else { instance = new ReactCompositeComponentWrapper(element); } } elseif (typeof node === 'string' || typeof node === 'number') { instance = ReactHostComponent.createInstanceForText(node); } else { invariant(false, 'Encountered invalid React node of type %s', typeof node); }
var ReactHostComponentInjection = { // This accepts a class that receives the tag string. This is a catch all // that can render any kind of tag. injectGenericComponentClass: function(componentClass) { genericComponentClass = componentClass; }, // This accepts a text component class that takes the text string to be // rendered as props. injectTextComponentClass: function(componentClass) { textComponentClass = componentClass; }, };
functioncreateInternalComponent(element) { invariant( genericComponentClass, 'There is no registered component for the tag %s', element.type, ); returnnew genericComponentClass(element); }
就是提供了两个方法来创建组件,而其中两个组件 class 的实现是通过其他模块注入进来的,那到底是从哪里注入进来的呢。 经过一番查找,发现是在 ReactDOMStackInjection.js 中注入的,我们看一下代码:
var ReactComponentEnvironment = require('ReactComponentEnvironment'); var ReactComponentBrowserEnvironment = require('ReactComponentBrowserEnvironment'); var ReactDOMComponent = require('ReactDOMComponent'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); var ReactDOMEmptyComponent = require('ReactDOMEmptyComponent'); var ReactDOMTextComponent = require('ReactDOMTextComponent'); var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy'); var ReactEmptyComponent = require('ReactEmptyComponent'); var ReactGenericBatching = require('ReactGenericBatching'); var ReactHostComponent = require('ReactHostComponent'); var ReactReconcileTransaction = require('ReactReconcileTransaction'); var ReactUpdates = require('ReactUpdates');
var findDOMNode = require('findDOMNode'); var getHostComponentFromComposite = require('getHostComponentFromComposite');
var transaction = new ReactDefaultBatchingStrategyTransaction();
var ReactDefaultBatchingStrategy = { isBatchingUpdates: false,
/** * Call the provided function in a context within which calls to `setState` * and friends are batched such that components aren't updated unnecessarily. */ batchedUpdates: function(callback, a, b, c, d, e) { var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;
// The code is written this way to avoid extra allocations if (alreadyBatchingUpdates) { // 如果当前 updates 已经完成,那么直接调用 callback return callback(a, b, c, d, e); } else { // 通过事务的方式去调用 callback return transaction.perform(callback, null, a, b, c, d, e); } }, };
var SELECTION_RESTORATION = { initialize: ReactInputSelection.getSelectionInformation, close: ReactInputSelection.restoreSelection, };
/** * Suppresses events (blur/focus) that could be inadvertently dispatched due to * high level DOM manipulations (like temporarily removing a text input from the * DOM). */ var EVENT_SUPPRESSION = { initialize: function() { var currentlyEnabled = ReactBrowserEventEmitter.isEnabled(); ReactBrowserEventEmitter.setEnabled(false); return currentlyEnabled; }, close: function(previouslyEnabled) { ReactBrowserEventEmitter.setEnabled(previouslyEnabled); }, };
/** * Provides a queue for collecting `componentDidMount` and * `componentDidUpdate` callbacks during the transaction. */ var ON_DOM_READY_QUEUEING = { initialize: function() { this.reactMountReady.reset(); }, close: function() { this.reactMountReady.notifyAll(); }, }; ... var TRANSACTION_WRAPPERS = [ SELECTION_RESTORATION, EVENT_SUPPRESSION, ON_DOM_READY_QUEUEING, ]; functionReactReconcileTransaction(useCreateElement) { this.reinitializeTransaction(); this.renderToStaticMarkup = false; this.reactMountReady = CallbackQueue.getPooled(); this.useCreateElement = useCreateElement; } ... var Mixin = { getTransactionWrappers: function() { return TRANSACTION_WRAPPERS; }, ... } Object.assign(ReactReconcileTransaction.prototype, Transaction, Mixin);
if (__DEV__) { // We allow auto-mocks to proceed as if they're returning null. if (renderedElement === undefined && inst.render._isMockFunction) { // This is probably bad practice. Consider warning here and // deprecating this convenience. renderedElement = null; } }