From 86ee9e84880cab9f3804e7e59ec75bb75a4cf455 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Sun, 11 Feb 2018 16:29:02 -0800 Subject: [PATCH] NativeMethodsMixin DEV-only methods should not warn (#12212) * Disable DEV-only warnings for RN NativeMethodsMixin/create-react-class * Tiny bit of cleanup * Make strict-mode suppression check a little more robust --- .../src/NativeMethodsMixin.js | 8 +++ .../src/ReactStrictModeWarnings.js | 13 ++--- ...eateReactClassIntegration-test.internal.js | 58 ++++++++++++++++++- 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/packages/react-native-renderer/src/NativeMethodsMixin.js b/packages/react-native-renderer/src/NativeMethodsMixin.js index e2cad55458..aec0442934 100644 --- a/packages/react-native-renderer/src/NativeMethodsMixin.js +++ b/packages/react-native-renderer/src/NativeMethodsMixin.js @@ -192,6 +192,8 @@ if (__DEV__) { !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps, 'Do not override existing functions.', ); + // TODO (bvaughn) Remove cWM and cWRP in a future version of React Native, + // Once these lifecycles have been remove from the reconciler. NativeMethodsMixin_DEV.componentWillMount = function() { throwOnStylesProp(this, this.props); }; @@ -204,6 +206,12 @@ if (__DEV__) { NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps = function(newProps) { throwOnStylesProp(this, newProps); }; + + // React may warn about cWM/cWRP/cWU methods being deprecated. + // Add a flag to suppress these warnings for this special case. + // TODO (bvaughn) Remove this flag once the above methods have been removed. + NativeMethodsMixin_DEV.componentWillMount.__suppressDeprecationWarning = true; + NativeMethodsMixin_DEV.componentWillReceiveProps.__suppressDeprecationWarning = true; } export default NativeMethodsMixin; diff --git a/packages/react-reconciler/src/ReactStrictModeWarnings.js b/packages/react-reconciler/src/ReactStrictModeWarnings.js index 8604526ad7..0afaa74d52 100644 --- a/packages/react-reconciler/src/ReactStrictModeWarnings.js +++ b/packages/react-reconciler/src/ReactStrictModeWarnings.js @@ -201,19 +201,16 @@ if (__DEV__) { } // Don't warn about react-lifecycles-compat polyfilled components. - // Note that it is sufficient to check for the presence of a - // single lifecycle, componentWillMount, with the polyfill flag. if ( typeof instance.componentWillMount === 'function' && - instance.componentWillMount.__suppressDeprecationWarning === true + instance.componentWillMount.__suppressDeprecationWarning !== true ) { - return; - } - - if (typeof instance.componentWillMount === 'function') { pendingComponentWillMountWarnings.push(fiber); } - if (typeof instance.componentWillReceiveProps === 'function') { + if ( + typeof instance.componentWillReceiveProps === 'function' && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== true + ) { pendingComponentWillReceivePropsWarnings.push(fiber); } if (typeof instance.componentWillUpdate === 'function') { diff --git a/packages/react/src/__tests__/createReactClassIntegration-test.internal.js b/packages/react/src/__tests__/createReactClassIntegration-test.internal.js index 2fcd864dde..d79a194996 100644 --- a/packages/react/src/__tests__/createReactClassIntegration-test.internal.js +++ b/packages/react/src/__tests__/createReactClassIntegration-test.internal.js @@ -10,17 +10,17 @@ 'use strict'; let React; -let ReactDOM; let ReactFeatureFlags; let createReactClass; describe('create-react-class-integration', () => { beforeEach(() => { + jest.resetModules(); + ReactFeatureFlags = require('shared/ReactFeatureFlags'); ReactFeatureFlags.warnAboutDeprecatedLifecycles = true; React = require('react'); - ReactDOM = require('react-dom'); createReactClass = require('create-react-class/factory')( React.Component, React.isValidElement, @@ -31,6 +31,8 @@ describe('create-react-class-integration', () => { // TODO (RFC #6) Merge this back into createReactClassIntegration-test once // the 'warnAboutDeprecatedLifecycles' feature flag has been removed. it('isMounted works', () => { + const ReactDOM = require('react-dom'); + const ops = []; let instance; const Component = createReactClass({ @@ -113,4 +115,56 @@ describe('create-react-class-integration', () => { 'after unmount: false', ]); }); + + describe('ReactNative NativeMethodsMixin', () => { + let ReactNative; + let NativeMethodsMixin; + + beforeEach(() => { + ReactNative = require('react-native-renderer'); + NativeMethodsMixin = + ReactNative.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED + .NativeMethodsMixin; + }); + + it('should not warn about default DEV-only legacy lifecycle methods', () => { + const View = createReactClass({ + mixins: [NativeMethodsMixin], + render: () => null, + }); + + ReactNative.render(, 1); + }); + + it('should warn if users specify their own legacy componentWillMount', () => { + const View = createReactClass({ + displayName: 'MyNativeComponent', + mixins: [NativeMethodsMixin], + componentWillMount: () => {}, + render: () => null, + }); + + expect(() => ReactNative.render(, 1)).toLowPriorityWarnDev( + 'componentWillMount is deprecated and will be removed in the next major version. ' + + 'Use componentDidMount instead. As a temporary workaround, ' + + 'you can rename to UNSAFE_componentWillMount.' + + '\n\nPlease update the following components: MyNativeComponent', + ); + }); + + it('should warn if users specify their own legacy componentWillReceiveProps', () => { + const View = createReactClass({ + displayName: 'MyNativeComponent', + mixins: [NativeMethodsMixin], + componentWillReceiveProps: () => {}, + render: () => null, + }); + + expect(() => ReactNative.render(, 1)).toLowPriorityWarnDev( + 'componentWillReceiveProps is deprecated and will be removed in the next major version. ' + + 'Use static getDerivedStateFromProps instead.' + + '\n\nPlease update the following components: MyNativeComponent', + ); + }); + }); });