Satyajit Sahoo 803cb61346 Show better error message when accessing React APIs on React Native
Summary:
**Motivation:**

Lots of examples on the web still have the old way to import React APIs from React Native. Also when someone upgrades to latest version of React Native without reading the release notes can get confused. This PR adds getters for  `createClass` and `Component` and throws an error with a better error message when they are accessed.

![screenshot_20160614-125622](https://cloud.githubusercontent.com/assets/1174278/16034600/47c70222-3230-11e6-9fe4-1a3493708829.png)

**Test plan:**

Trying to use `ReactNative.createClass` or `ReactNative.Component` will throw an error with this error message.

There's currently a bug in `symbolicateStackTrace` which actually crashes the app after showing the error due to the `stack` being null when updating the stack trace. But that's a separate issue which should be fixed separately. For now, to prevent the crash, we need to add the following before the return statement here - https://github.com/facebook/react-native/blob/master/Libraries/JavaScriptAppEn
Closes https://github.com/facebook/react-native/pull/8099

Differential Revision: D3430468

Pulled By: javache

fbshipit-source-id: c098e51e1f2c276d87eca6da3bd91a457d7840c5
2016-06-14 06:28:26 -07:00

231 lines
8.6 KiB
JavaScript

/**
* 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.
*
* @noflow - get/set properties not yet supported by flow. also `...require(x)` is broken #6560135
*/
'use strict';
const warning = require('fbjs/lib/warning');
if (__DEV__) {
const warningDedupe = {};
const addonWarn = function(prevName, newPackageName) {
warning(
warningDedupe[prevName],
'React.addons.' + prevName + ' is deprecated. Please import the "' +
newPackageName + '" package instead.'
);
warningDedupe[prevName] = true;
};
}
// Export React, plus some native additions.
const ReactNative = {
// Components
get ActivityIndicator() { return require('ActivityIndicator'); },
get ActivityIndicatorIOS() { return require('ActivityIndicatorIOS'); },
get ART() { return require('ReactNativeART'); },
get DatePickerIOS() { return require('DatePickerIOS'); },
get DrawerLayoutAndroid() { return require('DrawerLayoutAndroid'); },
get Image() { return require('Image'); },
get ImageEditor() { return require('ImageEditor'); },
get ImageStore() { return require('ImageStore'); },
get KeyboardAvoidingView() { return require('KeyboardAvoidingView'); },
get ListView() { return require('ListView'); },
get MapView() { return require('MapView'); },
get Modal() { return require('Modal'); },
get Navigator() { return require('Navigator'); },
get NavigatorIOS() { return require('NavigatorIOS'); },
get Picker() { return require('Picker'); },
get PickerIOS() { return require('PickerIOS'); },
get ProgressBarAndroid() { return require('ProgressBarAndroid'); },
get ProgressViewIOS() { return require('ProgressViewIOS'); },
get ScrollView() { return require('ScrollView'); },
get SegmentedControlIOS() { return require('SegmentedControlIOS'); },
get Slider() { return require('Slider'); },
get SliderIOS() { return require('SliderIOS'); },
get SnapshotViewIOS() { return require('SnapshotViewIOS'); },
get Switch() { return require('Switch'); },
get RecyclerViewBackedScrollView() { return require('RecyclerViewBackedScrollView'); },
get RefreshControl() { return require('RefreshControl'); },
get StatusBar() { return require('StatusBar'); },
get SwitchAndroid() { return require('SwitchAndroid'); },
get SwitchIOS() { return require('SwitchIOS'); },
get TabBarIOS() { return require('TabBarIOS'); },
get Text() { return require('Text'); },
get TextInput() { return require('TextInput'); },
get ToastAndroid() { return require('ToastAndroid'); },
get ToolbarAndroid() { return require('ToolbarAndroid'); },
get Touchable() { return require('Touchable'); },
get TouchableHighlight() { return require('TouchableHighlight'); },
get TouchableNativeFeedback() { return require('TouchableNativeFeedback'); },
get TouchableOpacity() { return require('TouchableOpacity'); },
get TouchableWithoutFeedback() { return require('TouchableWithoutFeedback'); },
get View() { return require('View'); },
get ViewPagerAndroid() { return require('ViewPagerAndroid'); },
get WebView() { return require('WebView'); },
// APIs
get ActionSheetIOS() { return require('ActionSheetIOS'); },
get AdSupportIOS() { return require('AdSupportIOS'); },
get Alert() { return require('Alert'); },
get AlertIOS() { return require('AlertIOS'); },
get Animated() { return require('Animated'); },
get AppRegistry() { return require('AppRegistry'); },
get AppState() { return require('AppState'); },
get AppStateIOS() { return require('AppStateIOS'); },
get AsyncStorage() { return require('AsyncStorage'); },
get BackAndroid() { return require('BackAndroid'); },
get CameraRoll() { return require('CameraRoll'); },
get Clipboard() { return require('Clipboard'); },
get DatePickerAndroid() { return require('DatePickerAndroid'); },
get Dimensions() { return require('Dimensions'); },
get Easing() { return require('Easing'); },
get ImagePickerIOS() { return require('ImagePickerIOS'); },
get IntentAndroid() { return require('IntentAndroid'); },
get InteractionManager() { return require('InteractionManager'); },
get Keyboard() { return require('Keyboard'); },
get LayoutAnimation() { return require('LayoutAnimation'); },
get Linking() { return require('Linking'); },
get LinkingIOS() { return require('LinkingIOS'); },
get NativeEventEmitter() { return require('NativeEventEmitter'); },
get NavigationExperimental() { return require('NavigationExperimental'); },
get NetInfo() { return require('NetInfo'); },
get PanResponder() { return require('PanResponder'); },
get PixelRatio() { return require('PixelRatio'); },
get PushNotificationIOS() { return require('PushNotificationIOS'); },
get Settings() { return require('Settings'); },
get StatusBarIOS() { return require('StatusBarIOS'); },
get StyleSheet() { return require('StyleSheet'); },
get Systrace() { return require('Systrace'); },
get TimePickerAndroid() { return require('TimePickerAndroid'); },
get UIManager() { return require('UIManager'); },
get Vibration() { return require('Vibration'); },
get VibrationIOS() { return require('VibrationIOS'); },
// Plugins
get DeviceEventEmitter() { return require('RCTDeviceEventEmitter'); },
get NativeAppEventEmitter() { return require('RCTNativeAppEventEmitter'); },
get NativeModules() { return require('NativeModules'); },
get Platform() { return require('Platform'); },
get processColor() { return require('processColor'); },
get requireNativeComponent() { return require('requireNativeComponent'); },
// Prop Types
get ColorPropType() { return require('ColorPropType'); },
get EdgeInsetsPropType() { return require('EdgeInsetsPropType'); },
get PointPropType() { return require('PointPropType'); },
// See http://facebook.github.io/react/docs/addons.html
addons: {
get LinkedStateMixin() {
if (__DEV__) {
addonWarn('LinkedStateMixin', 'react-addons-linked-state-mixin');
}
return require('LinkedStateMixin');
},
Perf: undefined,
get PureRenderMixin() {
if (__DEV__) {
addonWarn('PureRenderMixin', 'react-addons-pure-render-mixin');
}
return require('ReactComponentWithPureRenderMixin');
},
get TestModule() {
if (__DEV__) {
warning(
warningDedupe.TestModule,
'React.addons.TestModule is deprecated. ' +
'Use ReactNative.NativeModules.TestModule instead.'
);
warningDedupe.TestModule = true;
}
return require('NativeModules').TestModule;
},
TestUtils: undefined,
get batchedUpdates() {
if (__DEV__) {
warning(
warningDedupe.batchedUpdates,
'React.addons.batchedUpdates is deprecated. ' +
'Use ReactNative.unstable_batchedUpdates instead.'
);
warningDedupe.batchedUpdates = true;
}
return require('ReactUpdates').batchedUpdates;
},
get createFragment() {
if (__DEV__) {
addonWarn('createFragment', 'react-addons-create-fragment');
}
return require('ReactFragment').create;
},
get update() {
if (__DEV__) {
addonWarn('update', 'react-addons-update');
}
return require('update');
},
},
};
// Better error messages when accessing React APIs on ReactNative
if (__DEV__) {
const throwOnWrongReactAPI = require('throwOnWrongReactAPI');
const reactAPIs = [ 'createClass', 'Component' ];
for (const key of reactAPIs) {
Object.defineProperty(ReactNative, key, {
get() { throwOnWrongReactAPI(key); },
enumerable: false,
configurable: false
});
}
}
// Preserve getters with warnings on the internal ReactNative copy without
// invoking them.
const ReactNativeInternal = require('ReactNative');
function applyForwarding(key) {
if (__DEV__) {
Object.defineProperty(
ReactNative,
key,
Object.getOwnPropertyDescriptor(ReactNativeInternal, key)
);
return;
}
ReactNative[key] = ReactNativeInternal[key];
}
for (const key in ReactNativeInternal) {
applyForwarding(key);
}
if (__DEV__) {
Object.defineProperty(ReactNative.addons, 'Perf', {
enumerable: true,
get: () => {
if (__DEV__) {
addonWarn('Perf', 'react-addons-perf');
}
return require('ReactPerf');
}
});
Object.defineProperty(ReactNative.addons, 'TestUtils', {
enumerable: true,
get: () => {
if (__DEV__) {
addonWarn('update', 'react-addons-test-utils');
}
return require('ReactTestUtils');
}
});
}
module.exports = ReactNative;