/** * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ 'use strict'; var _prodInvariant = require('./reactProdInvariant'), _assign = require('object-assign'); var React = require('react/lib/React'); var ReactComponentEnvironment = require('./ReactComponentEnvironment'); var ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); var ReactErrorUtils = require('./ReactErrorUtils'); var ReactInstanceMap = require('./ReactInstanceMap'); var ReactInstrumentation = require('./ReactInstrumentation'); var ReactNodeTypes = require('./ReactNodeTypes'); var ReactReconciler = require('./ReactReconciler'); if (process.env.NODE_ENV !== 'production') { var checkReactTypeSpec = require('./checkReactTypeSpec'); } var emptyObject = require('fbjs/lib/emptyObject'); var invariant = require('fbjs/lib/invariant'); var shallowEqual = require('fbjs/lib/shallowEqual'); var shouldUpdateReactComponent = require('./shouldUpdateReactComponent'); var warning = require('fbjs/lib/warning'); var CompositeTypes = { ImpureClass: 0, PureClass: 1, StatelessFunctional: 2 }; function StatelessComponent(Component) {} StatelessComponent.prototype.render = function () { var Component = ReactInstanceMap.get(this)._currentElement.type; var element = Component(this.props, this.context, this.updater); warnIfInvalidElement(Component, element); return element; }; function warnIfInvalidElement(Component, element) { if (process.env.NODE_ENV !== 'production') { process.env.NODE_ENV !== 'production' ? warning(element === null || element === false || React.isValidElement(element), '%s(...): A valid React element (or null) must be returned. You may have ' + 'returned undefined, an array or some other invalid object.', Component.displayName || Component.name || 'Component') : void 0; process.env.NODE_ENV !== 'production' ? warning(!Component.childContextTypes, '%s(...): childContextTypes cannot be defined on a functional component.', Component.displayName || Component.name || 'Component') : void 0; } } function shouldConstruct(Component) { return !!(Component.prototype && Component.prototype.isReactComponent); } function isPureComponent(Component) { return !!(Component.prototype && Component.prototype.isPureReactComponent); } // Separated into a function to contain deoptimizations caused by try/finally. function measureLifeCyclePerf(fn, debugID, timerType) { if (debugID === 0) { // Top-level wrappers (see ReactMount) and empty components (see // ReactDOMEmptyComponent) are invisible to hooks and devtools. // Both are implementation details that should go away in the future. return fn(); } ReactInstrumentation.debugTool.onBeginLifeCycleTimer(debugID, timerType); try { return fn(); } finally { ReactInstrumentation.debugTool.onEndLifeCycleTimer(debugID, timerType); } } /** * ------------------ The Life-Cycle of a Composite Component ------------------ * * - constructor: Initialization of state. The instance is now retained. * - componentWillMount * - render * - [children's constructors] * - [children's componentWillMount and render] * - [children's componentDidMount] * - componentDidMount * * Update Phases: * - componentWillReceiveProps (only called if parent updated) * - shouldComponentUpdate * - componentWillUpdate * - render * - [children's constructors or receive props phases] * - componentDidUpdate * * - componentWillUnmount * - [children's componentWillUnmount] * - [children destroyed] * - (destroyed): The instance is now blank, released by React and ready for GC. * * ----------------------------------------------------------------------------- */ /** * An incrementing ID assigned to each component when it is mounted. This is * used to enforce the order in which `ReactUpdates` updates dirty components. * * @private */ var nextMountID = 1; /** * @lends {ReactCompositeComponent.prototype} */ var ReactCompositeComponent = { /** * Base constructor for all composite component. * * @param {ReactElement} element * @final * @internal */ construct: function (element) { this._currentElement = element; this._rootNodeID = 0; this._compositeType = null; this._instance = null; this._hostParent = null; this._hostContainerInfo = null; // See ReactUpdateQueue this._updateBatchNumber = null; this._pendingElement = null; this._pendingStateQueue = null; this._pendingReplaceState = false; this._pendingForceUpdate = false; this._renderedNodeType = null; this._renderedComponent = null; this._context = null; this._mountOrder = 0; this._topLevelWrapper = null; // See ReactUpdates and ReactUpdateQueue. this._pendingCallbacks = null; // ComponentWillUnmount shall only be called once this._calledComponentWillUnmount = false; if (process.env.NODE_ENV !== 'production') { this._warnedAboutRefsInRender = false; } }, /** * Initializes the component, renders markup, and registers event listeners. * * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction * @param {?object} hostParent * @param {?object} hostContainerInfo * @param {?object} context * @return {?string} Rendered markup to be inserted into the DOM. * @final * @internal */ mountComponent: function (transaction, hostParent, hostContainerInfo, context) { var _this = this; this._context = context; this._mountOrder = nextMountID++; this._hostParent = hostParent; this._hostContainerInfo = hostContainerInfo; var publicProps = this._currentElement.props; var publicContext = this._processContext(context); var Component = this._currentElement.type; var updateQueue = transaction.getUpdateQueue(); // Initialize the public class var doConstruct = shouldConstruct(Component); var inst = this._constructComponent(doConstruct, publicProps, publicContext, updateQueue); var renderedElement; // Support functional components if (!doConstruct && (inst == null || inst.render == null)) { renderedElement = inst; warnIfInvalidElement(Component, renderedElement); !(inst === null || inst === false || React.isValidElement(inst)) ? process.env.NODE_ENV !== 'production' ? invariant(false, '%s(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.', Component.displayName || Component.name || 'Component') : _prodInvariant('105', Component.displayName || Component.name || 'Component') : void 0; inst = new StatelessComponent(Component); this._compositeType = CompositeTypes.StatelessFunctional; } else { if (isPureComponent(Component)) { this._compositeType = CompositeTypes.PureClass; } else { this._compositeType = CompositeTypes.ImpureClass; } } if (process.env.NODE_ENV !== 'production') { // This will throw later in _renderValidatedComponent, but add an early // warning now to help debugging if (inst.render == null) { process.env.NODE_ENV !== 'production' ? warning(false, '%s(...): No `render` method found on the returned component ' + 'instance: you may have forgotten to define `render`.', Component.displayName || Component.name || 'Component') : void 0; } var propsMutated = inst.props !== publicProps; var componentName = Component.displayName || Component.name || 'Component'; process.env.NODE_ENV !== 'production' ? warning(inst.props === undefined || !propsMutated, '%s(...): When calling super() in `%s`, make sure to pass ' + "up the same props that your component's constructor was passed.", componentName, componentName) : void 0; } // These should be set up in the constructor, but as a convenience for // simpler class abstractions, we set them up after the fact. inst.props = publicProps; inst.context = publicContext; inst.refs = emptyObject; inst.updater = updateQueue; this._instance = inst; // Store a reference from the instance back to the internal representation ReactInstanceMap.set(inst, this); if (process.env.NODE_ENV !== 'production') { // Since plain JS classes are defined without any special initialization // logic, we can not catch common errors early. Therefore, we have to // catch them here, at initialization time, instead. process.env.NODE_ENV !== 'production' ? warning(!inst.getInitialState || inst.getInitialState.isReactClassApproved || inst.state, 'getInitialState was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Did you mean to define a state property instead?', this.getName() || 'a component') : void 0; process.env.NODE_ENV !== 'production' ? warning(!inst.getDefaultProps || inst.getDefaultProps.isReactClassApproved, 'getDefaultProps was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Use a static property to define defaultProps instead.', this.getName() || 'a component') : void 0; process.env.NODE_ENV !== 'production' ? warning(!inst.propTypes, 'propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', this.getName() || 'a component') : void 0; process.env.NODE_ENV !== 'production' ? warning(!inst.contextTypes, 'contextTypes was defined as an instance property on %s. Use a ' + 'static property to define contextTypes instead.', this.getName() || 'a component') : void 0; process.env.NODE_ENV !== 'production' ? warning(typeof inst.componentShouldUpdate !== 'function', '%s has a method called ' + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 'The name is phrased as a question because the function is ' + 'expected to return a value.', this.getName() || 'A component') : void 0; process.env.NODE_ENV !== 'production' ? warning(typeof inst.componentDidUnmount !== 'function', '%s has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + 'Did you mean componentWillUnmount()?', this.getName() || 'A component') : void 0; process.env.NODE_ENV !== 'production' ? warning(typeof inst.componentWillRecieveProps !== 'function', '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', this.getName() || 'A component') : void 0; } var initialState = inst.state; if (initialState === undefined) { inst.state = initialState = null; } !(typeof initialState === 'object' && !Array.isArray(initialState)) ? process.env.NODE_ENV !== 'production' ? invariant(false, '%s.state: must be set to an object or null', this.getName() || 'ReactCompositeComponent') : _prodInvariant('106', this.getName() || 'ReactCompositeComponent') : void 0; this._pendingStateQueue = null; this._pendingReplaceState = false; this._pendingForceUpdate = false; var markup; if (inst.unstable_handleError) { markup = this.performInitialMountWithErrorHandling(renderedElement, hostParent, hostContainerInfo, transaction, context); } else { markup = this.performInitialMount(renderedElement, hostParent, hostContainerInfo, transaction, context); } if (inst.componentDidMount) { if (process.env.NODE_ENV !== 'production') { transaction.getReactMountReady().enqueue(function () { measureLifeCyclePerf(function () { return inst.componentDidMount(); }, _this._debugID, 'componentDidMount'); }); } else { transaction.getReactMountReady().enqueue(inst.componentDidMount, inst); } } return markup; }, _constructComponent: function (doConstruct, publicProps, publicContext, updateQueue) { if (process.env.NODE_ENV !== 'production') { ReactCurrentOwner.current = this; try { return this._constructComponentWithoutOwner(doConstruct, publicProps, publicContext, updateQueue); } finally { ReactCurrentOwner.current = null; } } else { return this._constructComponentWithoutOwner(doConstruct, publicProps, publicContext, updateQueue); } }, _constructComponentWithoutOwner: function (doConstruct, publicProps, publicContext, updateQueue) { var Component = this._currentElement.type; if (doConstruct) { if (process.env.NODE_ENV !== 'production') { return measureLifeCyclePerf(function () { return new Component(publicProps, publicContext, updateQueue); }, this._debugID, 'ctor'); } else { return new Component(publicProps, publicContext, updateQueue); } } // This can still be an instance in case of factory components // but we'll count this as time spent rendering as the more common case. if (process.env.NODE_ENV !== 'production') { return measureLifeCyclePerf(function () { return Component(publicProps, publicContext, updateQueue); }, this._debugID, 'render'); } else { return Component(publicProps, publicContext, updateQueue); } }, performInitialMountWithErrorHandling: function (renderedElement, hostParent, hostContainerInfo, transaction, context) { var markup; var checkpoint = transaction.checkpoint(); try { markup = this.performInitialMount(renderedElement, hostParent, hostContainerInfo, transaction, context); } catch (e) { // Roll back to checkpoint, handle error (which may add items to the transaction), and take a new checkpoint transaction.rollback(checkpoint); this._instance.unstable_handleError(e); if (this._pendingStateQueue) { this._instance.state = this._processPendingState(this._instance.props, this._instance.context); } checkpoint = transaction.checkpoint(); this._renderedComponent.unmountComponent(true); transaction.rollback(checkpoint); // Try again - we've informed the component about the error, so they can render an error message this time. // If this throws again, the error will bubble up (and can be caught by a higher error boundary). markup = this.performInitialMount(renderedElement, hostParent, hostContainerInfo, transaction, context); } return markup; }, performInitialMount: function (renderedElement, hostParent, hostContainerInfo, transaction, context) { var inst = this._instance; var debugID = 0; if (process.env.NODE_ENV !== 'production') { debugID = this._debugID; } if (inst.componentWillMount) { if (process.env.NODE_ENV !== 'production') { measureLifeCyclePerf(function () { return inst.componentWillMount(); }, debugID, 'componentWillMount'); } else { inst.componentWillMount(); } // When mounting, calls to `setState` by `componentWillMount` will set // `this._pendingStateQueue` without triggering a re-render. if (this._pendingStateQueue) { inst.state = this._processPendingState(inst.props, inst.context); } } // If not a stateless component, we now render if (renderedElement === undefined) { renderedElement = this._renderValidatedComponent(); } var nodeType = ReactNodeTypes.getType(renderedElement); this._renderedNodeType = nodeType; var child = this._instantiateReactComponent(renderedElement, nodeType !== ReactNodeTypes.EMPTY /* shouldHaveDebugID */ ); this._renderedComponent = child; var markup = ReactReconciler.mountComponent(child, transaction, hostParent, hostContainerInfo, this._processChildContext(context), debugID); if (process.env.NODE_ENV !== 'production') { if (debugID !== 0) { var childDebugIDs = child._debugID !== 0 ? [child._debugID] : []; ReactInstrumentation.debugTool.onSetChildren(debugID, childDebugIDs); } } return markup; }, getHostNode: function () { return ReactReconciler.getHostNode(this._renderedComponent); }, /** * Releases any resources allocated by `mountComponent`. * * @final * @internal */ unmountComponent: function (safely) { if (!this._renderedComponent) { return; } var inst = this._instance; if (inst.componentWillUnmount && !inst._calledComponentWillUnmount) { inst._calledComponentWillUnmount = true; if (safely) { var name = this.getName() + '.componentWillUnmount()'; ReactErrorUtils.invokeGuardedCallback(name, inst.componentWillUnmount.bind(inst)); } else { if (process.env.NODE_ENV !== 'production') { measureLifeCyclePerf(function () { return inst.componentWillUnmount(); }, this._debugID, 'componentWillUnmount'); } else { inst.componentWillUnmount(); } } } if (this._renderedComponent) { ReactReconciler.unmountComponent(this._renderedComponent, safely); this._renderedNodeType = null; this._renderedComponent = null; this._instance = null; } // Reset pending fields // Even if this component is scheduled for another update in ReactUpdates, // it would still be ignored because these fields are reset. this._pendingStateQueue = null; this._pendingReplaceState = false; this._pendingForceUpdate = false; this._pendingCallbacks = null; this._pendingElement = null; // These fields do not really need to be reset since this object is no // longer accessible. this._context = null; this._rootNodeID = 0; this._topLevelWrapper = null; // Delete the reference from the instance to this internal representation // which allow the internals to be properly cleaned up even if the user // leaks a reference to the public instance. ReactInstanceMap.remove(inst); // Some existing components rely on inst.props even after they've been // destroyed (in event handlers). // TODO: inst.props = null; // TODO: inst.state = null; // TODO: inst.context = null; }, /** * Filters the context object to only contain keys specified in * `contextTypes` * * @param {object} context * @return {?object} * @private */ _maskContext: function (context) { var Component = this._currentElement.type; var contextTypes = Component.contextTypes; if (!contextTypes) { return emptyObject; } var maskedContext = {}; for (var contextName in contextTypes) { maskedContext[contextName] = context[contextName]; } return maskedContext; }, /** * Filters the context object to only contain keys specified in * `contextTypes`, and asserts that they are valid. * * @param {object} context * @return {?object} * @private */ _processContext: function (context) { var maskedContext = this._maskContext(context); if (process.env.NODE_ENV !== 'production') { var Component = this._currentElement.type; if (Component.contextTypes) { this._checkContextTypes(Component.contextTypes, maskedContext, 'context'); } } return maskedContext; }, /** * @param {object} currentContext * @return {object} * @private */ _processChildContext: function (currentContext) { var Component = this._currentElement.type; var inst = this._instance; var childContext; if (inst.getChildContext) { if (process.env.NODE_ENV !== 'production') { ReactInstrumentation.debugTool.onBeginProcessingChildContext(); try { childContext = inst.getChildContext(); } finally { ReactInstrumentation.debugTool.onEndProcessingChildContext(); } } else { childContext = inst.getChildContext(); } } if (childContext) { !(typeof Component.childContextTypes === 'object') ? process.env.NODE_ENV !== 'production' ? invariant(false, '%s.getChildContext(): childContextTypes must be defined in order to use getChildContext().', this.getName() || 'ReactCompositeComponent') : _prodInvariant('107', this.getName() || 'ReactCompositeComponent') : void 0; if (process.env.NODE_ENV !== 'production') { this._checkContextTypes(Component.childContextTypes, childContext, 'child context'); } for (var name in childContext) { !(name in Component.childContextTypes) ? process.env.NODE_ENV !== 'production' ? invariant(false, '%s.getChildContext(): key "%s" is not defined in childContextTypes.', this.getName() || 'ReactCompositeComponent', name) : _prodInvariant('108', this.getName() || 'ReactCompositeComponent', name) : void 0; } return _assign({}, currentContext, childContext); } return currentContext; }, /** * Assert that the context types are valid * * @param {object} typeSpecs Map of context field to a ReactPropType * @param {object} values Runtime values that need to be type-checked * @param {string} location e.g. "prop", "context", "child context" * @private */ _checkContextTypes: function (typeSpecs, values, location) { if (process.env.NODE_ENV !== 'production') { checkReactTypeSpec(typeSpecs, values, location, this.getName(), null, this._debugID); } }, receiveComponent: function (nextElement, transaction, nextContext) { var prevElement = this._currentElement; var prevContext = this._context; this._pendingElement = null; this.updateComponent(transaction, prevElement, nextElement, prevContext, nextContext); }, /** * If any of `_pendingElement`, `_pendingStateQueue`, or `_pendingForceUpdate` * is set, update the component. * * @param {ReactReconcileTransaction} transaction * @internal */ 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; } }, /** * Perform an update to a mounted component. The componentWillReceiveProps and * shouldComponentUpdate methods are called, then (assuming the update isn't * skipped) the remaining update lifecycle methods are called and the DOM * representation is updated. * * By default, this implements React's rendering and reconciliation algorithm. * Sophisticated clients may wish to override this. * * @param {ReactReconcileTransaction} transaction * @param {ReactElement} prevParentElement * @param {ReactElement} nextParentElement * @internal * @overridable */ updateComponent: function (transaction, prevParentElement, nextParentElement, prevUnmaskedContext, nextUnmaskedContext) { var inst = this._instance; !(inst != null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Attempted to update component `%s` that has already been unmounted (or failed to mount).', this.getName() || 'ReactCompositeComponent') : _prodInvariant('136', this.getName() || 'ReactCompositeComponent') : void 0; var willReceive = false; var nextContext; // Determine if the context has changed or not if (this._context === nextUnmaskedContext) { nextContext = inst.context; } else { nextContext = this._processContext(nextUnmaskedContext); willReceive = true; } var prevProps = prevParentElement.props; var nextProps = nextParentElement.props; // Not a simple state update but a props update if (prevParentElement !== nextParentElement) { willReceive = true; } // An update here will schedule an update but immediately set // _pendingStateQueue which will ensure that any state updates gets // immediately reconciled instead of waiting for the next batch. if (willReceive && inst.componentWillReceiveProps) { if (process.env.NODE_ENV !== 'production') { measureLifeCyclePerf(function () { return inst.componentWillReceiveProps(nextProps, nextContext); }, this._debugID, 'componentWillReceiveProps'); } else { inst.componentWillReceiveProps(nextProps, nextContext); } } var nextState = this._processPendingState(nextProps, nextContext); var shouldUpdate = true; if (!this._pendingForceUpdate) { if (inst.shouldComponentUpdate) { if (process.env.NODE_ENV !== 'production') { shouldUpdate = measureLifeCyclePerf(function () { return inst.shouldComponentUpdate(nextProps, nextState, nextContext); }, this._debugID, 'shouldComponentUpdate'); } else { shouldUpdate = inst.shouldComponentUpdate(nextProps, nextState, nextContext); } } else { if (this._compositeType === CompositeTypes.PureClass) { shouldUpdate = !shallowEqual(prevProps, nextProps) || !shallowEqual(inst.state, nextState); } } } if (process.env.NODE_ENV !== 'production') { process.env.NODE_ENV !== 'production' ? warning(shouldUpdate !== undefined, '%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.', this.getName() || 'ReactCompositeComponent') : void 0; } this._updateBatchNumber = null; if (shouldUpdate) { this._pendingForceUpdate = false; // Will set `this.props`, `this.state` and `this.context`. this._performComponentUpdate(nextParentElement, nextProps, nextState, nextContext, transaction, nextUnmaskedContext); } else { // If it's determined that a component should not update, we still want // to set props and state but we shortcut the rest of the update. this._currentElement = nextParentElement; this._context = nextUnmaskedContext; inst.props = nextProps; inst.state = nextState; inst.context = nextContext; } }, _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; }, /** * Merges new props and state, notifies delegate methods of update and * performs update. * * @param {ReactElement} nextElement Next element * @param {object} nextProps Next public object to set as properties. * @param {?object} nextState Next object to set as state. * @param {?object} nextContext Next public object to set as context. * @param {ReactReconcileTransaction} transaction * @param {?object} unmaskedContext * @private */ _performComponentUpdate: function (nextElement, nextProps, nextState, nextContext, transaction, unmaskedContext) { var _this2 = this; var inst = this._instance; var hasComponentDidUpdate = Boolean(inst.componentDidUpdate); var prevProps; var prevState; var prevContext; if (hasComponentDidUpdate) { prevProps = inst.props; prevState = inst.state; prevContext = inst.context; } if (inst.componentWillUpdate) { if (process.env.NODE_ENV !== 'production') { measureLifeCyclePerf(function () { return inst.componentWillUpdate(nextProps, nextState, nextContext); }, this._debugID, 'componentWillUpdate'); } else { inst.componentWillUpdate(nextProps, nextState, nextContext); } } this._currentElement = nextElement; this._context = unmaskedContext; inst.props = nextProps; inst.state = nextState; inst.context = nextContext; this._updateRenderedComponent(transaction, unmaskedContext); if (hasComponentDidUpdate) { if (process.env.NODE_ENV !== 'production') { transaction.getReactMountReady().enqueue(function () { measureLifeCyclePerf(inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext), _this2._debugID, 'componentDidUpdate'); }); } else { transaction.getReactMountReady().enqueue(inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext), inst); } } }, /** * Call the component's `render` method and update the DOM accordingly. * * @param {ReactReconcileTransaction} transaction * @internal */ _updateRenderedComponent: function (transaction, context) { var prevComponentInstance = this._renderedComponent; var prevRenderedElement = prevComponentInstance._currentElement; var nextRenderedElement = this._renderValidatedComponent(); var debugID = 0; if (process.env.NODE_ENV !== 'production') { debugID = this._debugID; } if (shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement)) { ReactReconciler.receiveComponent(prevComponentInstance, nextRenderedElement, transaction, this._processChildContext(context)); } else { var oldHostNode = ReactReconciler.getHostNode(prevComponentInstance); ReactReconciler.unmountComponent(prevComponentInstance, false); var nodeType = ReactNodeTypes.getType(nextRenderedElement); this._renderedNodeType = nodeType; var child = this._instantiateReactComponent(nextRenderedElement, nodeType !== ReactNodeTypes.EMPTY /* shouldHaveDebugID */ ); this._renderedComponent = child; var nextMarkup = ReactReconciler.mountComponent(child, transaction, this._hostParent, this._hostContainerInfo, this._processChildContext(context), debugID); if (process.env.NODE_ENV !== 'production') { if (debugID !== 0) { var childDebugIDs = child._debugID !== 0 ? [child._debugID] : []; ReactInstrumentation.debugTool.onSetChildren(debugID, childDebugIDs); } } this._replaceNodeWithMarkup(oldHostNode, nextMarkup, prevComponentInstance); } }, /** * Overridden in shallow rendering. * * @protected */ _replaceNodeWithMarkup: function (oldHostNode, nextMarkup, prevInstance) { ReactComponentEnvironment.replaceNodeWithMarkup(oldHostNode, nextMarkup, prevInstance); }, /** * @protected */ _renderValidatedComponentWithoutOwnerOrContext: function () { var inst = this._instance; var renderedElement; if (process.env.NODE_ENV !== 'production') { renderedElement = measureLifeCyclePerf(function () { return inst.render(); }, this._debugID, 'render'); } else { renderedElement = inst.render(); } if (process.env.NODE_ENV !== 'production') { // 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; } } return renderedElement; }, /** * @private */ _renderValidatedComponent: function () { var renderedElement; if (process.env.NODE_ENV !== 'production' || this._compositeType !== CompositeTypes.StatelessFunctional) { ReactCurrentOwner.current = this; try { renderedElement = this._renderValidatedComponentWithoutOwnerOrContext(); } finally { ReactCurrentOwner.current = null; } } else { renderedElement = this._renderValidatedComponentWithoutOwnerOrContext(); } !( // TODO: An `isValidNode` function would probably be more appropriate renderedElement === null || renderedElement === false || React.isValidElement(renderedElement)) ? process.env.NODE_ENV !== 'production' ? invariant(false, '%s.render(): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.', this.getName() || 'ReactCompositeComponent') : _prodInvariant('109', this.getName() || 'ReactCompositeComponent') : void 0; return renderedElement; }, /** * Lazily allocates the refs object and stores `component` as `ref`. * * @param {string} ref Reference name. * @param {component} component Component to store as `ref`. * @final * @private */ attachRef: function (ref, component) { var inst = this.getPublicInstance(); !(inst != null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Stateless function components cannot have refs.') : _prodInvariant('110') : void 0; var publicComponentInstance = component.getPublicInstance(); if (process.env.NODE_ENV !== 'production') { var componentName = component && component.getName ? component.getName() : 'a component'; process.env.NODE_ENV !== 'production' ? warning(publicComponentInstance != null || component._compositeType !== CompositeTypes.StatelessFunctional, 'Stateless function components cannot be given refs ' + '(See ref "%s" in %s created by %s). ' + 'Attempts to access this ref will fail.', ref, componentName, this.getName()) : void 0; } var refs = inst.refs === emptyObject ? inst.refs = {} : inst.refs; refs[ref] = publicComponentInstance; }, /** * Detaches a reference name. * * @param {string} ref Name to dereference. * @final * @private */ detachRef: function (ref) { var refs = this.getPublicInstance().refs; delete refs[ref]; }, /** * Get a text description of the component that can be used to identify it * in error messages. * @return {string} The name or null. * @internal */ getName: function () { var type = this._currentElement.type; var constructor = this._instance && this._instance.constructor; return type.displayName || constructor && constructor.displayName || type.name || constructor && constructor.name || null; }, /** * Get the publicly accessible representation of this component - i.e. what * is exposed by refs and returned by render. Can be null for stateless * components. * * @return {ReactComponent} the public component instance. * @internal */ getPublicInstance: function () { var inst = this._instance; if (this._compositeType === CompositeTypes.StatelessFunctional) { return null; } return inst; }, // Stub _instantiateReactComponent: null }; module.exports = ReactCompositeComponent;