diff --git a/packages/react-dom/src/__tests__/ReactDeprecationWarnings-test.internal.js b/packages/react-dom/src/__tests__/ReactDeprecationWarnings-test.internal.js new file mode 100644 index 0000000000000..d4413dd4e8752 --- /dev/null +++ b/packages/react-dom/src/__tests__/ReactDeprecationWarnings-test.internal.js @@ -0,0 +1,47 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @emails react-core + */ + +'use strict'; + +let React; +let ReactTestUtils; +let ReactFeatureFlags; + +describe('ReactDeprecationWarnings', () => { + beforeEach(() => { + jest.resetModules(); + React = require('react'); + ReactFeatureFlags = require('shared/ReactFeatureFlags'); + ReactTestUtils = require('react-dom/test-utils'); + ReactFeatureFlags.warnAboutDefaultPropsOnFunctionComponents = true; + }); + + afterEach(() => { + ReactFeatureFlags.warnAboutDefaultPropsOnFunctionComponents = false; + }); + + it('should warn when given defaultProps', () => { + function FunctionalComponent(props) { + return null; + } + + FunctionalComponent.defaultProps = { + testProp: true, + }; + + expect(() => + ReactTestUtils.renderIntoDocument(), + ).toWarnDev( + 'Warning: FunctionalComponent: Support for defaultProps ' + + 'will be removed from function components in a future major ' + + 'release. Use JavaScript default parameters instead.', + {withoutStack: true}, + ); + }); +}); diff --git a/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js b/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js index f6359e20190b0..685a1cffb97e3 100644 --- a/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js @@ -365,6 +365,8 @@ describe('ReactFunctionComponent', () => { ); }); + // TODO: change this test after we deprecate default props support + // for function components it('should support default props and prop types', () => { function Child(props) { return
{props.test}
; diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index f95a80b12a942..18c076bd39571 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -62,6 +62,7 @@ import { enableSuspenseServerRenderer, enableFlareAPI, enableFundamentalAPI, + warnAboutDefaultPropsOnFunctionComponents, } from 'shared/ReactFeatureFlags'; import invariant from 'shared/invariant'; import shallowEqual from 'shared/shallowEqual'; @@ -187,6 +188,7 @@ export let didWarnAboutReassigningProps; let didWarnAboutMaxDuration; let didWarnAboutRevealOrder; let didWarnAboutTailOptions; +let didWarnAboutDefaultPropsOnFunctionComponent; if (__DEV__) { didWarnAboutBadClass = {}; @@ -198,6 +200,7 @@ if (__DEV__) { didWarnAboutMaxDuration = false; didWarnAboutRevealOrder = {}; didWarnAboutTailOptions = {}; + didWarnAboutDefaultPropsOnFunctionComponent = {}; } export function reconcileChildren( @@ -1424,6 +1427,23 @@ function validateFunctionComponentInDev(workInProgress: Fiber, Component: any) { } } + if ( + warnAboutDefaultPropsOnFunctionComponents && + Component.defaultProps !== undefined + ) { + const componentName = getComponentName(Component) || 'Unknown'; + + if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) { + warningWithoutStack( + false, + '%s: Support for defaultProps will be removed from function components ' + + 'in a future major release. Use JavaScript default parameters instead.', + componentName, + ); + didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true; + } + } + if (typeof Component.getDerivedStateFromProps === 'function') { const componentName = getComponentName(Component) || 'Unknown'; diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 259334080ccb0..ac92811f09541 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -83,3 +83,8 @@ export const enableUserBlockingEvents = false; // in the update queue. This allows reporting and tracing of what is causing // the user to see a loading state. export const enableSuspenseCallback = false; + +// Part of the simplification of React.createElement so we can eventually move +// from React.createElement to React.jsx +// https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md +export const warnAboutDefaultPropsOnFunctionComponents = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 8982c8f996d57..08baee4c30ca5 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -38,6 +38,7 @@ export const warnAboutMissingMockScheduler = true; export const revertPassiveEffectsChange = false; export const enableUserBlockingEvents = false; export const enableSuspenseCallback = false; +export const warnAboutDefaultPropsOnFunctionComponents = false; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 4183657076ea7..e1bb4ecae4bfd 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -33,6 +33,7 @@ export const warnAboutMissingMockScheduler = false; export const revertPassiveEffectsChange = false; export const enableUserBlockingEvents = false; export const enableSuspenseCallback = false; +export const warnAboutDefaultPropsOnFunctionComponents = false; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactFeatureFlags.persistent.js b/packages/shared/forks/ReactFeatureFlags.persistent.js index 568626d09c4b1..c392336fc5188 100644 --- a/packages/shared/forks/ReactFeatureFlags.persistent.js +++ b/packages/shared/forks/ReactFeatureFlags.persistent.js @@ -33,6 +33,7 @@ export const warnAboutMissingMockScheduler = true; export const revertPassiveEffectsChange = false; export const enableUserBlockingEvents = false; export const enableSuspenseCallback = false; +export const warnAboutDefaultPropsOnFunctionComponents = false; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 80174516fcc83..a38d1f5ff8218 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -33,6 +33,7 @@ export const warnAboutMissingMockScheduler = false; export const revertPassiveEffectsChange = false; export const enableUserBlockingEvents = false; export const enableSuspenseCallback = false; +export const warnAboutDefaultPropsOnFunctionComponents = false; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 37a2a80402498..c8f1beb3e6288 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -33,6 +33,7 @@ export const enableJSXTransformAPI = true; export const warnAboutMissingMockScheduler = true; export const enableUserBlockingEvents = false; export const enableSuspenseCallback = true; +export const warnAboutDefaultPropsOnFunctionComponents = false; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 6451c459028eb..284416c8255b2 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -78,6 +78,8 @@ export const warnAboutMissingMockScheduler = true; export const enableSuspenseCallback = true; +export const warnAboutDefaultPropsOnFunctionComponents = false; + // Flow magic to verify the exports of this file match the original version. // eslint-disable-next-line no-unused-vars type Check<_X, Y: _X, X: Y = _X> = null;