128 lines
4.9 KiB
JavaScript
128 lines
4.9 KiB
JavaScript
/**
|
|
* 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 ReactCompositeComponent = require('./ReactCompositeComponent');
|
|
var ReactEmptyComponent = require('./ReactEmptyComponent');
|
|
var ReactHostComponent = require('./ReactHostComponent');
|
|
|
|
var getNextDebugID = require('react/lib/getNextDebugID');
|
|
var invariant = require('fbjs/lib/invariant');
|
|
var warning = require('fbjs/lib/warning');
|
|
|
|
// To avoid a cyclic dependency, we create the final class in this module
|
|
var ReactCompositeComponentWrapper = function (element) {
|
|
this.construct(element);
|
|
};
|
|
|
|
function getDeclarationErrorAddendum(owner) {
|
|
if (owner) {
|
|
var name = owner.getName();
|
|
if (name) {
|
|
return ' Check the render method of `' + name + '`.';
|
|
}
|
|
}
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Check if the type reference is a known internal type. I.e. not a user
|
|
* provided composite type.
|
|
*
|
|
* @param {function} type
|
|
* @return {boolean} Returns true if this is a valid internal type.
|
|
*/
|
|
function isInternalComponentType(type) {
|
|
return typeof type === 'function' && typeof type.prototype !== 'undefined' && typeof type.prototype.mountComponent === 'function' && typeof type.prototype.receiveComponent === 'function';
|
|
}
|
|
|
|
/**
|
|
* Given a ReactNode, create an instance that will actually be mounted.
|
|
*
|
|
* @param {ReactNode} node
|
|
* @param {boolean} shouldHaveDebugID
|
|
* @return {object} A new instance of the element's constructor.
|
|
* @protected
|
|
*/
|
|
function instantiateReactComponent(node, shouldHaveDebugID) {
|
|
var instance;
|
|
|
|
if (node === null || node === false) {
|
|
instance = ReactEmptyComponent.create(instantiateReactComponent);
|
|
} else if (typeof node === 'object') {
|
|
var element = node;
|
|
var type = element.type;
|
|
if (typeof type !== 'function' && typeof type !== 'string') {
|
|
var info = '';
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) {
|
|
info += ' You likely forgot to export your component from the file ' + 'it\'s defined in.';
|
|
}
|
|
}
|
|
info += getDeclarationErrorAddendum(element._owner);
|
|
!false ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s', type == null ? type : typeof type, info) : _prodInvariant('130', type == null ? type : typeof type, info) : void 0;
|
|
}
|
|
|
|
// Special case string values
|
|
if (typeof element.type === 'string') {
|
|
instance = ReactHostComponent.createInternalComponent(element);
|
|
} else if (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);
|
|
}
|
|
} else if (typeof node === 'string' || typeof node === 'number') {
|
|
instance = ReactHostComponent.createInstanceForText(node);
|
|
} else {
|
|
!false ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Encountered invalid React node of type %s', typeof node) : _prodInvariant('131', typeof node) : void 0;
|
|
}
|
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
process.env.NODE_ENV !== 'production' ? warning(typeof instance.mountComponent === 'function' && typeof instance.receiveComponent === 'function' && typeof instance.getHostNode === 'function' && typeof instance.unmountComponent === 'function', 'Only React Components can be mounted.') : void 0;
|
|
}
|
|
|
|
// These two fields are used by the DOM and ART diffing algorithms
|
|
// respectively. Instead of using expandos on components, we should be
|
|
// storing the state needed by the diffing algorithms elsewhere.
|
|
instance._mountIndex = 0;
|
|
instance._mountImage = null;
|
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
instance._debugID = shouldHaveDebugID ? getNextDebugID() : 0;
|
|
}
|
|
|
|
// Internal instances should fully constructed at this point, so they should
|
|
// not get any new fields added to them at this point.
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
if (Object.preventExtensions) {
|
|
Object.preventExtensions(instance);
|
|
}
|
|
}
|
|
|
|
return instance;
|
|
}
|
|
|
|
_assign(ReactCompositeComponentWrapper.prototype, ReactCompositeComponent, {
|
|
_instantiateReactComponent: instantiateReactComponent
|
|
});
|
|
|
|
module.exports = instantiateReactComponent; |