diff --git a/flow/react-native-host-hooks.js b/flow/react-native-host-hooks.js index 1e4a048ae4..7c0a1b5c39 100644 --- a/flow/react-native-host-hooks.js +++ b/flow/react-native-host-hooks.js @@ -40,4 +40,6 @@ declare module 'UIManager' { declare function setChildren() : void; declare function updateView() : void; } -declare module 'View' { } +declare module 'View' { + declare var exports : typeof ReactComponent; +} diff --git a/grunt/config/browserify.js b/grunt/config/browserify.js index 332af66f22..3c06303a3c 100644 --- a/grunt/config/browserify.js +++ b/grunt/config/browserify.js @@ -19,13 +19,8 @@ var SECRET_INTERNALS_NAME = 'React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_ var shimSharedModulesFiles = { './ReactCurrentOwner': SECRET_INTERNALS_NAME + '.ReactCurrentOwner', './ReactComponentTreeHook': SECRET_INTERNALS_NAME + '.ReactComponentTreeHook', - // The methods we used here are exposed on the main React export. - // TODO: Change all renderer code to require the isomorphic React directly - // instead of these internals. + // Use the global, anywhere we require React './React': 'React', - './ReactElement': 'React', - './ReactPropTypes': 'React.PropTypes', - './ReactChildren': 'React.Children', }; // We can access these as absolute or relative. We need to shim both. diff --git a/gulpfile.js b/gulpfile.js index 20b54944eb..d5bd834620 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -111,20 +111,11 @@ var moduleMapReact = Object.assign( ); var rendererSharedState = { + // Alias + React: 'react/lib/React', // Shared state ReactCurrentOwner: 'react/lib/ReactCurrentOwner', ReactComponentTreeHook: 'react/lib/ReactComponentTreeHook', - - // TODO: Move to shared since these are actually shared and can be copied. - ReactPropTypeLocations: 'react/lib/ReactPropTypeLocations', - ReactPropTypesSecret: 'react/lib/ReactPropTypesSecret', - checkReactTypeSpec: 'react/lib/checkReactTypeSpec', - - // TODO: Update the source to just use the React module. - React: 'react/lib/React', - ReactElement: 'react/lib/ReactElement', - ReactPropTypes: 'react/lib/ReactPropTypes', - ReactChildren: 'react/lib/ReactChildren', }; var moduleMapReactDOM = Object.assign( diff --git a/src/isomorphic/classic/element/ReactElement.js b/src/isomorphic/classic/element/ReactElement.js index 64a0e13e14..9544a8cc73 100644 --- a/src/isomorphic/classic/element/ReactElement.js +++ b/src/isomorphic/classic/element/ReactElement.js @@ -17,11 +17,7 @@ var warning = require('warning'); var canDefineProperty = require('canDefineProperty'); var hasOwnProperty = Object.prototype.hasOwnProperty; -// The Symbol used to tag the ReactElement type. If there is no native Symbol -// nor polyfill, then a plain number is used for performance. -var REACT_ELEMENT_TYPE = - (typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element')) || - 0xeac7; +var REACT_ELEMENT_TYPE = require('ReactElementSymbol'); var RESERVED_PROPS = { key: true, @@ -390,6 +386,4 @@ ReactElement.isValidElement = function(object) { ); }; -ReactElement.REACT_ELEMENT_TYPE = REACT_ELEMENT_TYPE; - module.exports = ReactElement; diff --git a/src/renderers/dom/client/ReactMount.js b/src/renderers/dom/client/ReactMount.js index ec158c1754..d7f24aaf38 100644 --- a/src/renderers/dom/client/ReactMount.js +++ b/src/renderers/dom/client/ReactMount.js @@ -13,12 +13,12 @@ var DOMLazyTree = require('DOMLazyTree'); var DOMProperty = require('DOMProperty'); +var React = require('React'); var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter'); var ReactCurrentOwner = require('ReactCurrentOwner'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); var ReactDOMContainerInfo = require('ReactDOMContainerInfo'); var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); -var ReactElement = require('ReactElement'); var ReactFeatureFlags = require('ReactFeatureFlags'); var ReactInstanceMap = require('ReactInstanceMap'); var ReactInstrumentation = require('ReactInstrumentation'); @@ -423,7 +423,7 @@ var ReactMount = { _renderSubtreeIntoContainer: function(parentComponent, nextElement, container, callback) { ReactUpdateQueue.validateCallback(callback, 'ReactDOM.render'); invariant( - ReactElement.isValidElement(nextElement), + React.isValidElement(nextElement), 'ReactDOM.render(): Invalid component element.%s', ( typeof nextElement === 'string' ? @@ -450,7 +450,7 @@ var ReactMount = { 'for your app.' ); - var nextWrappedElement = ReactElement.createElement( + var nextWrappedElement = React.createElement( TopLevelWrapper, { child: nextElement } ); diff --git a/src/renderers/dom/client/wrappers/LinkedValueUtils.js b/src/renderers/dom/client/wrappers/LinkedValueUtils.js index d13630d6f5..22a10279d5 100644 --- a/src/renderers/dom/client/wrappers/LinkedValueUtils.js +++ b/src/renderers/dom/client/wrappers/LinkedValueUtils.js @@ -11,7 +11,7 @@ 'use strict'; -var ReactPropTypes = require('ReactPropTypes'); +var React = require('React'); var ReactPropTypeLocations = require('ReactPropTypeLocations'); var ReactPropTypesSecret = require('ReactPropTypesSecret'); @@ -84,7 +84,7 @@ var propTypes = { 'set either `onChange` or `readOnly`.' ); }, - onChange: ReactPropTypes.func, + onChange: React.PropTypes.func, }; var loggedTypeFailures = {}; diff --git a/src/renderers/dom/client/wrappers/ReactDOMOption.js b/src/renderers/dom/client/wrappers/ReactDOMOption.js index 295f961d03..2a2a28a180 100644 --- a/src/renderers/dom/client/wrappers/ReactDOMOption.js +++ b/src/renderers/dom/client/wrappers/ReactDOMOption.js @@ -11,7 +11,7 @@ 'use strict'; -var ReactChildren = require('ReactChildren'); +var React = require('React'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); var ReactDOMSelect = require('ReactDOMSelect'); @@ -23,7 +23,7 @@ function flattenChildren(children) { // Flatten children and warn if they aren't strings or numbers; // invalid types are ignored. - ReactChildren.forEach(children, function(child) { + React.Children.forEach(children, function(child) { if (child == null) { return; } diff --git a/src/renderers/dom/server/ReactServerRendering.js b/src/renderers/dom/server/ReactServerRendering.js index 64de3870bf..ff08fe8ff0 100644 --- a/src/renderers/dom/server/ReactServerRendering.js +++ b/src/renderers/dom/server/ReactServerRendering.js @@ -10,9 +10,9 @@ */ 'use strict'; +var React = require('React'); var ReactDOMContainerInfo = require('ReactDOMContainerInfo'); var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy'); -var ReactElement = require('ReactElement'); var ReactInstrumentation = require('ReactInstrumentation'); var ReactMarkupChecksum = require('ReactMarkupChecksum'); var ReactReconciler = require('ReactReconciler'); @@ -80,7 +80,7 @@ function renderToStringImpl(element, makeStaticMarkup) { */ function renderToString(element) { invariant( - ReactElement.isValidElement(element), + React.isValidElement(element), 'renderToString(): You must pass a valid ReactElement.' ); return renderToStringImpl(element, false); @@ -93,7 +93,7 @@ function renderToString(element) { */ function renderToStaticMarkup(element) { invariant( - ReactElement.isValidElement(element), + React.isValidElement(element), 'renderToStaticMarkup(): You must pass a valid ReactElement.' ); return renderToStringImpl(element, true); diff --git a/src/renderers/native/ReactNative.js b/src/renderers/native/ReactNative.js index 0305ff2447..23648da925 100644 --- a/src/renderers/native/ReactNative.js +++ b/src/renderers/native/ReactNative.js @@ -16,7 +16,6 @@ var ReactNativeComponentTree = require('ReactNativeComponentTree'); var ReactNativeDefaultInjection = require('ReactNativeDefaultInjection'); -var ReactElement = require('ReactElement'); var ReactNativeMount = require('ReactNativeMount'); var ReactUpdates = require('ReactUpdates'); @@ -25,7 +24,7 @@ var findNodeHandle = require('findNodeHandle'); ReactNativeDefaultInjection.inject(); var render = function( - element: ReactElement, + element: ReactElement, mountInto: number, callback?: ?(() => void) ): ?ReactComponent { diff --git a/src/renderers/native/ReactNativeDefaultInjection.js b/src/renderers/native/ReactNativeDefaultInjection.js index 42f3d115b4..4d15ab5771 100644 --- a/src/renderers/native/ReactNativeDefaultInjection.js +++ b/src/renderers/native/ReactNativeDefaultInjection.js @@ -22,9 +22,9 @@ require('InitializeJavaScriptAppEngine'); var EventPluginHub = require('EventPluginHub'); var EventPluginUtils = require('EventPluginUtils'); var RCTEventEmitter = require('RCTEventEmitter'); +var React = require('React'); var ReactComponentEnvironment = require('ReactComponentEnvironment'); var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy'); -var ReactElement = require('ReactElement'); var ReactEmptyComponent = require('ReactEmptyComponent'); var ReactNativeBridgeEventPlugin = require('ReactNativeBridgeEventPlugin'); var ReactHostComponent = require('ReactHostComponent'); @@ -83,7 +83,7 @@ function inject() { // Can't import View at the top because it depends on React to make its composite var View = require('View'); return new ReactSimpleEmptyComponent( - ReactElement.createElement(View, { + React.createElement(View, { collapsable: true, style: { position: 'absolute' }, }), diff --git a/src/renderers/native/ReactNativeMount.js b/src/renderers/native/ReactNativeMount.js index 080fe428f4..2d508631ab 100644 --- a/src/renderers/native/ReactNativeMount.js +++ b/src/renderers/native/ReactNativeMount.js @@ -11,7 +11,7 @@ */ 'use strict'; -var ReactElement = require('ReactElement'); +var React = require('React'); var ReactInstrumentation = require('ReactInstrumentation'); var ReactNativeContainerInfo = require('ReactNativeContainerInfo'); var ReactNativeTagHandles = require('ReactNativeTagHandles'); @@ -35,9 +35,9 @@ if (__DEV__) { TopLevelWrapper.displayName = 'TopLevelWrapper'; } TopLevelWrapper.prototype.render = function() { - // this.props is actually a ReactElement - return this.props; + return this.props.child; }; +TopLevelWrapper.isReactTopLevelWrapper = true; /** * Mounts this component and inserts it into the DOM. @@ -99,25 +99,20 @@ var ReactNativeMount = { * @param {containerTag} containerView Handle to native view tag */ renderComponent: function( - nextElement: ReactElement, + nextElement: ReactElement<*>, containerTag: number, callback?: ?(() => void) ): ?ReactComponent { - var nextWrappedElement = new ReactElement( + var nextWrappedElement = React.createElement( TopLevelWrapper, - null, - null, - null, - null, - null, - nextElement + { child: nextElement } ); var topRootNodeID = containerTag; var prevComponent = ReactNativeMount._instancesByContainerID[topRootNodeID]; if (prevComponent) { var prevWrappedElement = prevComponent._currentElement; - var prevElement = prevWrappedElement.props; + var prevElement = prevWrappedElement.props.child; if (shouldUpdateReactComponent(prevElement, nextElement)) { ReactUpdateQueue.enqueueElementInternal(prevComponent, nextWrappedElement, emptyObject); if (callback) { diff --git a/src/renderers/shared/fiber/ReactChildFiber.js b/src/renderers/shared/fiber/ReactChildFiber.js index c3621c30ad..a0e5608b62 100644 --- a/src/renderers/shared/fiber/ReactChildFiber.js +++ b/src/renderers/shared/fiber/ReactChildFiber.js @@ -18,9 +18,7 @@ import type { PriorityLevel } from 'ReactPriorityLevel'; import type { ReactNodeList } from 'ReactTypes'; -var { - REACT_ELEMENT_TYPE, -} = require('ReactElement'); +var REACT_ELEMENT_TYPE = require('ReactElementSymbol'); var { REACT_COROUTINE_TYPE, REACT_YIELD_TYPE, diff --git a/src/renderers/shared/fiber/ReactFiber.js b/src/renderers/shared/fiber/ReactFiber.js index 2bcfe3f496..fb3d6f9723 100644 --- a/src/renderers/shared/fiber/ReactFiber.js +++ b/src/renderers/shared/fiber/ReactFiber.js @@ -26,8 +26,6 @@ var { YieldComponent, } = ReactTypeOfWork; -var ReactElement = require('ReactElement'); - var { NoWork, } = require('ReactPriorityLevel'); @@ -201,7 +199,8 @@ exports.createHostContainerFiber = function() { return fiber; }; -exports.createFiberFromElement = function(element : ReactElement, priorityLevel : PriorityLevel) { +exports.createFiberFromElement = function(element : ReactElement<*>, priorityLevel : PriorityLevel) { +// $FlowFixMe: ReactElement.key is currently defined as ?string but should be defined as null | string in Flow. const fiber = createFiberFromElementType(element.type, element.key); fiber.pendingProps = element.props; fiber.pendingWorkPriority = priorityLevel; diff --git a/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js b/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js index ec3f31d41a..13db6d1bed 100644 --- a/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js +++ b/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js @@ -11,9 +11,9 @@ 'use strict'; +var React = require('React'); var ReactComponentEnvironment = require('ReactComponentEnvironment'); var ReactCurrentOwner = require('ReactCurrentOwner'); -var ReactElement = require('ReactElement'); var ReactErrorUtils = require('ReactErrorUtils'); var ReactInstanceMap = require('ReactInstanceMap'); var ReactInstrumentation = require('ReactInstrumentation'); @@ -49,7 +49,7 @@ StatelessComponent.prototype.render = function() { function warnIfInvalidElement(Component, element) { if (__DEV__) { warning( - element === null || element === false || ReactElement.isValidElement(element), + 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' @@ -212,7 +212,7 @@ var ReactCompositeComponentMixin = { invariant( inst === null || inst === false || - ReactElement.isValidElement(inst), + React.isValidElement(inst), '%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' @@ -1078,7 +1078,7 @@ var ReactCompositeComponentMixin = { invariant( // TODO: An `isValidNode` function would probably be more appropriate renderedComponent === null || renderedComponent === false || - ReactElement.isValidElement(renderedComponent), + React.isValidElement(renderedComponent), '%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' diff --git a/src/renderers/shared/stack/reconciler/ReactNodeTypes.js b/src/renderers/shared/stack/reconciler/ReactNodeTypes.js index 2b5e40376d..7b8d6f2094 100644 --- a/src/renderers/shared/stack/reconciler/ReactNodeTypes.js +++ b/src/renderers/shared/stack/reconciler/ReactNodeTypes.js @@ -14,7 +14,7 @@ type ReactNodeType = 0 | 1 | 2; -var ReactElement = require('ReactElement'); +var React = require('React'); var invariant = require('invariant'); @@ -26,7 +26,7 @@ var ReactNodeTypes = { getType: function(node: ReactElement): ReactNodeType { if (node === null || node === false) { return ReactNodeTypes.EMPTY; - } else if (ReactElement.isValidElement(node)) { + } else if (React.isValidElement(node)) { if (typeof node.type === 'function') { return ReactNodeTypes.COMPOSITE; } else { diff --git a/src/renderers/testing/ReactTestMount.js b/src/renderers/testing/ReactTestMount.js index c022b9f356..d964a1390a 100644 --- a/src/renderers/testing/ReactTestMount.js +++ b/src/renderers/testing/ReactTestMount.js @@ -11,7 +11,7 @@ */ 'use strict'; -var ReactElement = require('ReactElement'); +var React = require('React'); var ReactReconciler = require('ReactReconciler'); var ReactUpdates = require('ReactUpdates'); @@ -31,9 +31,9 @@ if (__DEV__) { TopLevelWrapper.displayName = 'TopLevelWrapper'; } TopLevelWrapper.prototype.render = function() { - // this.props is actually a ReactElement - return this.props; + return this.props.child; }; +TopLevelWrapper.isReactTopLevelWrapper = true; /** * Mounts this component and inserts it into the DOM. @@ -88,14 +88,9 @@ ReactTestInstance.prototype.update = function(nextElement) { this._component, "ReactTestRenderer: .update() can't be called after unmount." ); - var nextWrappedElement = new ReactElement( + var nextWrappedElement = React.createElement( TopLevelWrapper, - null, - null, - null, - null, - null, - nextElement + { child: nextElement } ); var component = this._component; ReactUpdates.batchedUpdates(function() { @@ -142,14 +137,9 @@ var ReactTestMount = { render: function( nextElement: ReactElement ): ReactTestInstance { - var nextWrappedElement = new ReactElement( + var nextWrappedElement = React.createElement( TopLevelWrapper, - null, - null, - null, - null, - null, - nextElement + { child: nextElement } ); var instance = instantiateReactComponent(nextWrappedElement, false); diff --git a/src/isomorphic/classic/types/ReactPropTypeLocationNames.js b/src/shared/types/ReactPropTypeLocationNames.js similarity index 100% rename from src/isomorphic/classic/types/ReactPropTypeLocationNames.js rename to src/shared/types/ReactPropTypeLocationNames.js diff --git a/src/isomorphic/classic/types/ReactPropTypeLocations.js b/src/shared/types/ReactPropTypeLocations.js similarity index 100% rename from src/isomorphic/classic/types/ReactPropTypeLocations.js rename to src/shared/types/ReactPropTypeLocations.js diff --git a/src/isomorphic/classic/types/ReactPropTypesSecret.js b/src/shared/types/ReactPropTypesSecret.js similarity index 100% rename from src/isomorphic/classic/types/ReactPropTypesSecret.js rename to src/shared/types/ReactPropTypesSecret.js diff --git a/src/isomorphic/classic/types/checkReactTypeSpec.js b/src/shared/types/checkReactTypeSpec.js similarity index 100% rename from src/isomorphic/classic/types/checkReactTypeSpec.js rename to src/shared/types/checkReactTypeSpec.js diff --git a/src/shared/utils/ReactElementSymbol.js b/src/shared/utils/ReactElementSymbol.js new file mode 100644 index 0000000000..7547e2471b --- /dev/null +++ b/src/shared/utils/ReactElementSymbol.js @@ -0,0 +1,20 @@ +/** + * Copyright 2014-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. + * + * @providesModule ReactElementSymbol + */ + +'use strict'; + +// The Symbol used to tag the ReactElement type. If there is no native Symbol +// nor polyfill, then a plain number is used for performance. +var REACT_ELEMENT_TYPE = + (typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element')) || + 0xeac7; + +module.exports = REACT_ELEMENT_TYPE; diff --git a/src/shared/utils/traverseAllChildren.js b/src/shared/utils/traverseAllChildren.js index 20d6e8eb52..60b5f147aa 100644 --- a/src/shared/utils/traverseAllChildren.js +++ b/src/shared/utils/traverseAllChildren.js @@ -12,7 +12,7 @@ 'use strict'; var ReactCurrentOwner = require('ReactCurrentOwner'); -var ReactElement = require('ReactElement'); +var REACT_ELEMENT_TYPE = require('ReactElementSymbol'); var getIteratorFn = require('getIteratorFn'); var invariant = require('invariant'); @@ -22,6 +22,12 @@ var warning = require('warning'); var SEPARATOR = '.'; var SUBSEPARATOR = ':'; +/** + * This is inlined from ReactElement since this file is shared between + * isomorphic and renderers. We could extract this to a + * + */ + /** * TODO: Test that a single child and an array with one item have the same key * pattern. @@ -71,7 +77,9 @@ function traverseAllChildrenImpl( if (children === null || type === 'string' || type === 'number' || - ReactElement.isValidElement(children)) { + // The following is inlined from ReactElement. This means we can optimize + // some checks. React Fiber also inlines this logic for similar purposes. + (type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE)) { callback( traverseContext, children, diff --git a/src/test/ReactTestUtils.js b/src/test/ReactTestUtils.js index 5689f8432c..810f273940 100644 --- a/src/test/ReactTestUtils.js +++ b/src/test/ReactTestUtils.js @@ -19,7 +19,6 @@ var React = require('React'); var ReactDefaultInjection = require('ReactDefaultInjection'); var ReactDOM = require('ReactDOM'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); -var ReactElement = require('ReactElement'); var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter'); var ReactCompositeComponent = require('ReactCompositeComponent'); var ReactInstanceMap = require('ReactInstanceMap'); @@ -61,7 +60,7 @@ function findAllInRenderedTreeInternal(inst, test) { ); } } else if ( - ReactElement.isValidElement(currentElement) && + React.isValidElement(currentElement) && typeof currentElement.type === 'function' ) { ret = ret.concat( @@ -92,12 +91,12 @@ var ReactTestUtils = { }, isElement: function(element) { - return ReactElement.isValidElement(element); + return React.isValidElement(element); }, isElementOfType: function(inst, convenienceConstructor) { return ( - ReactElement.isValidElement(inst) && + React.isValidElement(inst) && inst.type === convenienceConstructor ); }, @@ -108,7 +107,7 @@ var ReactTestUtils = { isDOMComponentElement: function(inst) { return !!(inst && - ReactElement.isValidElement(inst) && + React.isValidElement(inst) && !!inst.tagName); }, @@ -136,7 +135,7 @@ var ReactTestUtils = { }, isCompositeComponentElement: function(inst) { - if (!ReactElement.isValidElement(inst)) { + if (!React.isValidElement(inst)) { return false; } // We check the prototype of the type that will get mounted, not the @@ -440,7 +439,7 @@ ReactShallowRenderer.prototype.render = function(element, context) { ReactDefaultInjection.inject(); invariant( - ReactElement.isValidElement(element), + React.isValidElement(element), 'ReactShallowRenderer render(): Invalid component element.%s', typeof element === 'function' ? ' Instead of passing a component class, make sure to instantiate ' +