From 2eafcd45dbd42f750df1ab9aa3770fed5cdf11ae Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Sat, 9 Apr 2016 04:17:34 -0700 Subject: [PATCH] Add deprecation warnings for split of the react and react-native packages Summary:This adds deprecation warnings that correspond to what React 0.14 did for the web. I.e. `React.render` -> `ReactNative.render` but also `ReactNative.createClass` -> `React.createClass`. This hopefully means that it will become easier and more idiomatic to write components that are decoupled from the react-native package. It will be clear when you take on react-native as a dependency such as when using findNodeHandle. This codemod is a little more invasive for React Native because the common stuff often used the `react-native` package. For web only the uncommon stuff needed to move. Reviewed By: spicyj Differential Revision: D3148860 fb-gh-sync-id: d87628d2089a2e012ad6ad50dd0a20ccec5e6c45 fbshipit-source-id: d87628d2089a2e012ad6ad50dd0a20ccec5e6c45 --- Libraries/ReactNative/React.js | 31 ++++- Libraries/ReactNative/ReactNative.js | 147 +++++------------------ Libraries/ReactNative/ReactNativeImpl.js | 64 ++++++++++ Libraries/react-native/react-native.js | 22 +++- 4 files changed, 145 insertions(+), 119 deletions(-) create mode 100644 Libraries/ReactNative/ReactNativeImpl.js diff --git a/Libraries/ReactNative/React.js b/Libraries/ReactNative/React.js index 9cd4464f2860c9..368b3baf5ce0d7 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 148a366663efdd..a553947d0f23f3 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; -} - -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]; - } + 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; + }, + }); } -}; +} -// 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.' - ); - } - element._owner = ReactCurrentOwner.current; - if (element.type.defaultProps) { - resolveDefaultProps(element); + 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; + }, + }); } - 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 00000000000000..608798e6afd61e --- /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 f52968e6678b84..e18435b8639407 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,