diff --git a/Libraries/ReactNative/React.js b/Libraries/ReactNative/React.js index 9cd4464f2..368b3baf5 100644 --- a/Libraries/ReactNative/React.js +++ b/Libraries/ReactNative/React.js @@ -11,4 +11,33 @@ */ 'use strict'; -module.exports = require('ReactNative'); +const ReactIsomorphic = require('ReactIsomorphic'); +const ReactNativeImpl = require('ReactNativeImpl'); +const warning = require('warning'); + +const React = { ...ReactIsomorphic }; + +const dedupe = {}; + +for (const key in ReactNativeImpl) { + React[key] = ReactNativeImpl[key]; + if (__DEV__) { + Object.defineProperty(React, key, { + get: function() { + warning( + dedupe[key], + 'React.' + key + ' is deprecated. Use ReactNative.' + key + + ' from the "react-native" package instead.' + ); + dedupe[key] = true; + return ReactNativeImpl[key]; + }, + set: function(value) { + // Useful for hacky solutions like createExamplePage. + ReactNativeImpl[key] = value; + }, + }); + } +} + +module.exports = React; diff --git a/Libraries/ReactNative/ReactNative.js b/Libraries/ReactNative/ReactNative.js index 148a36666..a553947d0 100644 --- a/Libraries/ReactNative/ReactNative.js +++ b/Libraries/ReactNative/ReactNative.js @@ -11,128 +11,47 @@ */ 'use strict'; -// Require ReactNativeDefaultInjection first for its side effects of setting up -// the JS environment -var ReactNativeDefaultInjection = require('ReactNativeDefaultInjection'); +const ReactIsomorphic = require('ReactIsomorphic'); +const ReactNativeImpl = require('ReactNativeImpl'); +const warning = require('warning'); -var ReactChildren = require('ReactChildren'); -var ReactClass = require('ReactClass'); -var ReactComponent = require('ReactComponent'); -var ReactCurrentOwner = require('ReactCurrentOwner'); -var ReactElement = require('ReactElement'); -var ReactElementValidator = require('ReactElementValidator'); -var ReactInstanceHandles = require('ReactInstanceHandles'); -var ReactNativeMount = require('ReactNativeMount'); -var ReactPropTypes = require('ReactPropTypes'); -var ReactUpdates = require('ReactUpdates'); +const ReactNative = { ...ReactNativeImpl }; -var findNodeHandle = require('findNodeHandle'); -var invariant = require('fbjs/lib/invariant'); -var onlyChild = require('onlyChild'); -var warning = require('fbjs/lib/warning'); - -ReactNativeDefaultInjection.inject(); - -var createElement = ReactElement.createElement; -var createFactory = ReactElement.createFactory; -var cloneElement = ReactElement.cloneElement; +const dedupe = {}; if (__DEV__) { - createElement = ReactElementValidator.createElement; - createFactory = ReactElementValidator.createFactory; - cloneElement = ReactElementValidator.cloneElement; + for (const key in ReactNativeImpl) { + Object.defineProperty(ReactNative, key, { + get: function() { + return ReactNativeImpl[key]; + }, + set: function(value) { + // Useful for hacky solutions like createExamplePage. + ReactNativeImpl[key] = value; + }, + }); + } } -var resolveDefaultProps = function(element) { - // Could be optimized, but not currently in heavy use. - var defaultProps = element.type.defaultProps; - var props = element.props; - for (var propName in defaultProps) { - if (props[propName] === undefined) { - props[propName] = defaultProps[propName]; - } - } -}; - -// Experimental optimized element creation -var augmentElement = function(element: ReactElement): ReactElement { +for (const key in ReactIsomorphic) { + ReactNative[key] = ReactIsomorphic[key]; if (__DEV__) { - invariant( - false, - 'This optimized path should never be used in DEV mode because ' + - 'it does not provide validation. Check your JSX transform.' - ); + Object.defineProperty(ReactNative, key, { + get: function() { + warning( + dedupe[key], + 'ReactNative.' + key + ' is deprecated. Use React.' + key + + ' from the "react" package instead.' + ); + dedupe[key] = true; + return ReactIsomorphic[key]; + }, + set: function(value) { + // Useful for hacky solutions like createExamplePage. + ReactIsomorphic[key] = value; + }, + }); } - element._owner = ReactCurrentOwner.current; - if (element.type.defaultProps) { - resolveDefaultProps(element); - } - return element; -}; - -var render = function( - element: ReactElement, - mountInto: number, - callback?: ?(() => void) -): ?ReactComponent { - return ReactNativeMount.renderComponent(element, mountInto, callback); -}; - -var ReactNative = { - hasReactNativeInitialized: false, - Children: { - map: ReactChildren.map, - forEach: ReactChildren.forEach, - count: ReactChildren.count, - toArray: ReactChildren.toArray, - only: onlyChild - }, - Component: ReactComponent, - PropTypes: ReactPropTypes, - createClass: ReactClass.createClass, - createElement: createElement, - createFactory: createFactory, - cloneElement: cloneElement, - _augmentElement: augmentElement, - findNodeHandle: findNodeHandle, - render: render, - unmountComponentAtNode: ReactNativeMount.unmountComponentAtNode, - - /* eslint-disable camelcase */ - unstable_batchedUpdates: ReactUpdates.batchedUpdates, - /* eslint-enable camelcase */ - - // Hook for JSX spread, don't use this for anything else. - __spread: Object.assign, - - unmountComponentAtNodeAndRemoveContainer: ReactNativeMount.unmountComponentAtNodeAndRemoveContainer, - isValidClass: ReactElement.isValidFactory, - isValidElement: ReactElement.isValidElement, - - // Deprecations (remove for 0.13) - renderComponent: function( - element: ReactElement, - mountInto: number, - callback?: ?(() => void) - ): ?ReactComponent { - warning('Use React.render instead of React.renderComponent'); - return ReactNative.render(element, mountInto, callback); - }, -}; - -// Inject the runtime into a devtools global hook regardless of browser. -// Allows for debugging when the hook is injected on the page. -/* globals __REACT_DEVTOOLS_GLOBAL_HOOK__ */ -if ( - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') { - __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({ - CurrentOwner: ReactCurrentOwner, - InstanceHandles: ReactInstanceHandles, - Mount: ReactNativeMount, - Reconciler: require('ReactReconciler'), - TextComponent: require('ReactNativeTextComponent'), - }); } module.exports = ReactNative; diff --git a/Libraries/ReactNative/ReactNativeImpl.js b/Libraries/ReactNative/ReactNativeImpl.js new file mode 100644 index 000000000..608798e6a --- /dev/null +++ b/Libraries/ReactNative/ReactNativeImpl.js @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2015-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 ReactNativeImpl + * @flow + */ +'use strict'; + +// Require ReactNativeDefaultInjection first for its side effects of setting up +// the JS environment +var ReactNativeDefaultInjection = require('ReactNativeDefaultInjection'); + +var ReactCurrentOwner = require('ReactCurrentOwner'); +var ReactElement = require('ReactElement'); +var ReactInstanceHandles = require('ReactInstanceHandles'); +var ReactNativeMount = require('ReactNativeMount'); +var ReactUpdates = require('ReactUpdates'); + +var findNodeHandle = require('findNodeHandle'); + +ReactNativeDefaultInjection.inject(); + +var render = function( + element: ReactElement, + mountInto: number, + callback?: ?(() => void) +): ?ReactComponent { + return ReactNativeMount.renderComponent(element, mountInto, callback); +}; + +var ReactNative = { + hasReactNativeInitialized: false, + findNodeHandle: findNodeHandle, + render: render, + unmountComponentAtNode: ReactNativeMount.unmountComponentAtNode, + + /* eslint-disable camelcase */ + unstable_batchedUpdates: ReactUpdates.batchedUpdates, + /* eslint-enable camelcase */ + + unmountComponentAtNodeAndRemoveContainer: ReactNativeMount.unmountComponentAtNodeAndRemoveContainer, +}; + +// Inject the runtime into a devtools global hook regardless of browser. +// Allows for debugging when the hook is injected on the page. +/* globals __REACT_DEVTOOLS_GLOBAL_HOOK__ */ +if ( + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') { + __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({ + CurrentOwner: ReactCurrentOwner, + InstanceHandles: ReactInstanceHandles, + Mount: ReactNativeMount, + Reconciler: require('ReactReconciler'), + TextComponent: require('ReactNativeTextComponent'), + }); +} + +module.exports = ReactNative; diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js index f52968e66..e18435b86 100644 --- a/Libraries/react-native/react-native.js +++ b/Libraries/react-native/react-native.js @@ -115,12 +115,26 @@ var ReactNative = { get createFragment() { return require('ReactFragment').create; }, get update() { return require('update'); }, }, - - // Note: this must be placed last to prevent eager - // evaluation of the getter-wrapped submodules above - ...require('React'), }; +// Preserve getters with warnings on the internal ReactNative copy without +// invoking them. +var ReactNativeInternal = require('ReactNative'); +function applyForwarding(key) { + if (__DEV__) { + Object.defineProperty( + ReactNative, + key, + Object.getOwnPropertyDescriptor(ReactNativeInternal, key) + ); + return; + } + ReactNative[key] = ReactNativeInternal[key]; +} +for (var key in ReactNativeInternal) { + applyForwarding(key); +} + if (__DEV__) { Object.defineProperty(ReactNative.addons, 'Perf', { enumerable: true,