Skip to content

Commit 857deb2

Browse files
authored
Warn when Using DefaultProps on Function Components (#16210)
As part of the process to deprecate defaultProps on function components (as per a larger proposal outlined in (https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md)), add a warning whenever someone does this.
1 parent e047270 commit 857deb2

10 files changed

+81
-0
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @emails react-core
8+
*/
9+
10+
'use strict';
11+
12+
let React;
13+
let ReactTestUtils;
14+
let ReactFeatureFlags;
15+
16+
describe('ReactDeprecationWarnings', () => {
17+
beforeEach(() => {
18+
jest.resetModules();
19+
React = require('react');
20+
ReactFeatureFlags = require('shared/ReactFeatureFlags');
21+
ReactTestUtils = require('react-dom/test-utils');
22+
ReactFeatureFlags.warnAboutDefaultPropsOnFunctionComponents = true;
23+
});
24+
25+
afterEach(() => {
26+
ReactFeatureFlags.warnAboutDefaultPropsOnFunctionComponents = false;
27+
});
28+
29+
it('should warn when given defaultProps', () => {
30+
function FunctionalComponent(props) {
31+
return null;
32+
}
33+
34+
FunctionalComponent.defaultProps = {
35+
testProp: true,
36+
};
37+
38+
expect(() =>
39+
ReactTestUtils.renderIntoDocument(<FunctionalComponent />),
40+
).toWarnDev(
41+
'Warning: FunctionalComponent: Support for defaultProps ' +
42+
'will be removed from function components in a future major ' +
43+
'release. Use JavaScript default parameters instead.',
44+
{withoutStack: true},
45+
);
46+
});
47+
});

packages/react-dom/src/__tests__/ReactFunctionComponent-test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,8 @@ describe('ReactFunctionComponent', () => {
365365
);
366366
});
367367

368+
// TODO: change this test after we deprecate default props support
369+
// for function components
368370
it('should support default props and prop types', () => {
369371
function Child(props) {
370372
return <div>{props.test}</div>;

packages/react-reconciler/src/ReactFiberBeginWork.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ import {
6262
enableSuspenseServerRenderer,
6363
enableFlareAPI,
6464
enableFundamentalAPI,
65+
warnAboutDefaultPropsOnFunctionComponents,
6566
} from 'shared/ReactFeatureFlags';
6667
import invariant from 'shared/invariant';
6768
import shallowEqual from 'shared/shallowEqual';
@@ -187,6 +188,7 @@ export let didWarnAboutReassigningProps;
187188
let didWarnAboutMaxDuration;
188189
let didWarnAboutRevealOrder;
189190
let didWarnAboutTailOptions;
191+
let didWarnAboutDefaultPropsOnFunctionComponent;
190192

191193
if (__DEV__) {
192194
didWarnAboutBadClass = {};
@@ -198,6 +200,7 @@ if (__DEV__) {
198200
didWarnAboutMaxDuration = false;
199201
didWarnAboutRevealOrder = {};
200202
didWarnAboutTailOptions = {};
203+
didWarnAboutDefaultPropsOnFunctionComponent = {};
201204
}
202205

203206
export function reconcileChildren(
@@ -1424,6 +1427,23 @@ function validateFunctionComponentInDev(workInProgress: Fiber, Component: any) {
14241427
}
14251428
}
14261429

1430+
if (
1431+
warnAboutDefaultPropsOnFunctionComponents &&
1432+
Component.defaultProps !== undefined
1433+
) {
1434+
const componentName = getComponentName(Component) || 'Unknown';
1435+
1436+
if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) {
1437+
warningWithoutStack(
1438+
false,
1439+
'%s: Support for defaultProps will be removed from function components ' +
1440+
'in a future major release. Use JavaScript default parameters instead.',
1441+
componentName,
1442+
);
1443+
didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true;
1444+
}
1445+
}
1446+
14271447
if (typeof Component.getDerivedStateFromProps === 'function') {
14281448
const componentName = getComponentName(Component) || 'Unknown';
14291449

packages/shared/ReactFeatureFlags.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,8 @@ export const enableUserBlockingEvents = false;
8383
// in the update queue. This allows reporting and tracing of what is causing
8484
// the user to see a loading state.
8585
export const enableSuspenseCallback = false;
86+
87+
// Part of the simplification of React.createElement so we can eventually move
88+
// from React.createElement to React.jsx
89+
// https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md
90+
export const warnAboutDefaultPropsOnFunctionComponents = false;

packages/shared/forks/ReactFeatureFlags.native-fb.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export const warnAboutMissingMockScheduler = true;
3838
export const revertPassiveEffectsChange = false;
3939
export const enableUserBlockingEvents = false;
4040
export const enableSuspenseCallback = false;
41+
export const warnAboutDefaultPropsOnFunctionComponents = false;
4142

4243
// Only used in www builds.
4344
export function addUserTimingListener() {

packages/shared/forks/ReactFeatureFlags.native-oss.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export const warnAboutMissingMockScheduler = false;
3333
export const revertPassiveEffectsChange = false;
3434
export const enableUserBlockingEvents = false;
3535
export const enableSuspenseCallback = false;
36+
export const warnAboutDefaultPropsOnFunctionComponents = false;
3637

3738
// Only used in www builds.
3839
export function addUserTimingListener() {

packages/shared/forks/ReactFeatureFlags.persistent.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export const warnAboutMissingMockScheduler = true;
3333
export const revertPassiveEffectsChange = false;
3434
export const enableUserBlockingEvents = false;
3535
export const enableSuspenseCallback = false;
36+
export const warnAboutDefaultPropsOnFunctionComponents = false;
3637

3738
// Only used in www builds.
3839
export function addUserTimingListener() {

packages/shared/forks/ReactFeatureFlags.test-renderer.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export const warnAboutMissingMockScheduler = false;
3333
export const revertPassiveEffectsChange = false;
3434
export const enableUserBlockingEvents = false;
3535
export const enableSuspenseCallback = false;
36+
export const warnAboutDefaultPropsOnFunctionComponents = false;
3637

3738
// Only used in www builds.
3839
export function addUserTimingListener() {

packages/shared/forks/ReactFeatureFlags.test-renderer.www.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export const enableJSXTransformAPI = true;
3333
export const warnAboutMissingMockScheduler = true;
3434
export const enableUserBlockingEvents = false;
3535
export const enableSuspenseCallback = true;
36+
export const warnAboutDefaultPropsOnFunctionComponents = false;
3637

3738
// Only used in www builds.
3839
export function addUserTimingListener() {

packages/shared/forks/ReactFeatureFlags.www.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ export const warnAboutMissingMockScheduler = true;
7878

7979
export const enableSuspenseCallback = true;
8080

81+
export const warnAboutDefaultPropsOnFunctionComponents = false;
82+
8183
// Flow magic to verify the exports of this file match the original version.
8284
// eslint-disable-next-line no-unused-vars
8385
type Check<_X, Y: _X, X: Y = _X> = null;

0 commit comments

Comments
 (0)