Skip to content

Commit 3385865

Browse files
sebmarkbageacdlite
authored andcommitted
Enable warning for defaultProps on function components for everyone (#25699)
This also fixes a gap where were weren't warning on memo components.
1 parent 73bfaa1 commit 3385865

20 files changed

+225
-41
lines changed

packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,11 @@ describe('ReactHooksInspectionIntegration', () => {
882882

883883
await LazyFoo;
884884

885-
Scheduler.unstable_flushAll();
885+
expect(() => {
886+
Scheduler.unstable_flushAll();
887+
}).toErrorDev([
888+
'Foo: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.',
889+
]);
886890

887891
const childFiber = renderer.root._currentFiber();
888892
const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ describe('ReactDOMFizzServer', () => {
264264
}
265265

266266
// @gate experimental
267+
// @gate !warnAboutDefaultPropsOnFunctionComponents || !__DEV__
267268
it('should asynchronously load a lazy component', async () => {
268269
let resolveA;
269270
const LazyA = React.lazy(() => {

packages/react-dom/src/__tests__/ReactDeprecationWarnings-test.internal.js renamed to packages/react-dom/src/__tests__/ReactDeprecationWarnings-test.js

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
'use strict';
1111

1212
let React;
13-
let ReactFeatureFlags;
1413
let ReactNoop;
1514
let Scheduler;
1615
let JSXDEVRuntime;
@@ -19,19 +18,11 @@ describe('ReactDeprecationWarnings', () => {
1918
beforeEach(() => {
2019
jest.resetModules();
2120
React = require('react');
22-
ReactFeatureFlags = require('shared/ReactFeatureFlags');
2321
ReactNoop = require('react-noop-renderer');
2422
Scheduler = require('scheduler');
2523
if (__DEV__) {
2624
JSXDEVRuntime = require('react/jsx-dev-runtime');
2725
}
28-
ReactFeatureFlags.warnAboutDefaultPropsOnFunctionComponents = true;
29-
ReactFeatureFlags.warnAboutStringRefs = true;
30-
});
31-
32-
afterEach(() => {
33-
ReactFeatureFlags.warnAboutDefaultPropsOnFunctionComponents = false;
34-
ReactFeatureFlags.warnAboutStringRefs = false;
3526
});
3627

3728
it('should warn when given defaultProps', () => {
@@ -51,6 +42,27 @@ describe('ReactDeprecationWarnings', () => {
5142
);
5243
});
5344

45+
it('should warn when given defaultProps on a memoized function', () => {
46+
const MemoComponent = React.memo(function FunctionalComponent(props) {
47+
return null;
48+
});
49+
50+
MemoComponent.defaultProps = {
51+
testProp: true,
52+
};
53+
54+
ReactNoop.render(
55+
<div>
56+
<MemoComponent />
57+
</div>,
58+
);
59+
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
60+
'Warning: FunctionalComponent: Support for defaultProps ' +
61+
'will be removed from memo components in a future major ' +
62+
'release. Use JavaScript default parameters instead.',
63+
);
64+
});
65+
5466
it('should warn when given string refs', () => {
5567
class RefComponent extends React.Component {
5668
render() {
@@ -74,9 +86,7 @@ describe('ReactDeprecationWarnings', () => {
7486
);
7587
});
7688

77-
it('should not warn when owner and self are the same for string refs', () => {
78-
ReactFeatureFlags.warnAboutStringRefs = false;
79-
89+
it('should warn when owner and self are the same for string refs', () => {
8090
class RefComponent extends React.Component {
8191
render() {
8292
return null;
@@ -87,7 +97,11 @@ describe('ReactDeprecationWarnings', () => {
8797
return <RefComponent ref="refComponent" __self={this} />;
8898
}
8999
}
90-
ReactNoop.renderLegacySyncRoot(<Component />);
100+
expect(() => {
101+
ReactNoop.renderLegacySyncRoot(<Component />);
102+
}).toErrorDev([
103+
'Component "Component" contains the string ref "refComponent". Support for string refs will be removed in a future major release.',
104+
]);
91105
expect(Scheduler).toFlushWithoutYielding();
92106
});
93107

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,11 +367,12 @@ describe('ReactFunctionComponent', () => {
367367
Child.defaultProps = {test: 2};
368368
Child.propTypes = {test: PropTypes.string};
369369

370-
expect(() => ReactTestUtils.renderIntoDocument(<Child />)).toErrorDev(
370+
expect(() => ReactTestUtils.renderIntoDocument(<Child />)).toErrorDev([
371+
'Warning: Child: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.',
371372
'Warning: Failed prop type: Invalid prop `test` of type `number` ' +
372373
'supplied to `Child`, expected `string`.\n' +
373374
' in Child (at **)',
374-
);
375+
]);
375376
});
376377

377378
it('should receive context', () => {

packages/react-reconciler/src/ReactFiberBeginWork.new.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,20 @@ function updateMemoComponent(
496496
getComponentNameFromType(type),
497497
);
498498
}
499+
if (
500+
warnAboutDefaultPropsOnFunctionComponents &&
501+
Component.defaultProps !== undefined
502+
) {
503+
const componentName = getComponentNameFromType(type) || 'Unknown';
504+
if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) {
505+
console.error(
506+
'%s: Support for defaultProps will be removed from memo components ' +
507+
'in a future major release. Use JavaScript default parameters instead.',
508+
componentName,
509+
);
510+
didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true;
511+
}
512+
}
499513
}
500514
const child = createFiberFromTypeAndProps(
501515
Component.type,

packages/react-reconciler/src/ReactFiberBeginWork.old.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,20 @@ function updateMemoComponent(
496496
getComponentNameFromType(type),
497497
);
498498
}
499+
if (
500+
warnAboutDefaultPropsOnFunctionComponents &&
501+
Component.defaultProps !== undefined
502+
) {
503+
const componentName = getComponentNameFromType(type) || 'Unknown';
504+
if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) {
505+
console.error(
506+
'%s: Support for defaultProps will be removed from memo components ' +
507+
'in a future major release. Use JavaScript default parameters instead.',
508+
componentName,
509+
);
510+
didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true;
511+
}
512+
}
499513
}
500514
const child = createFiberFromTypeAndProps(
501515
Component.type,

packages/react-reconciler/src/ReactFiberClassComponent.new.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ let warnOnInvalidCallback;
9696
let didWarnAboutDirectlyAssigningPropsToState;
9797
let didWarnAboutContextTypeAndContextTypes;
9898
let didWarnAboutInvalidateContextType;
99+
let didWarnAboutLegacyContext;
99100

100101
if (__DEV__) {
101102
didWarnAboutStateAssignmentForComponent = new Set();
@@ -106,6 +107,7 @@ if (__DEV__) {
106107
didWarnAboutUndefinedDerivedState = new Set();
107108
didWarnAboutContextTypeAndContextTypes = new Set();
108109
didWarnAboutInvalidateContextType = new Set();
110+
didWarnAboutLegacyContext = new Set();
109111

110112
const didWarnOnInvalidCallback = new Set();
111113

@@ -435,6 +437,39 @@ function checkClassInstance(workInProgress: Fiber, ctor: any, newProps: any) {
435437
);
436438
}
437439
} else {
440+
if (
441+
ctor.childContextTypes &&
442+
!didWarnAboutLegacyContext.has(ctor) &&
443+
// Strict Mode has its own warning for legacy context, so we can skip
444+
// this one.
445+
(workInProgress.mode & StrictLegacyMode) === NoMode
446+
) {
447+
didWarnAboutLegacyContext.add(ctor);
448+
console.error(
449+
'%s uses the legacy childContextTypes API which is no longer ' +
450+
'supported and will be removed in the next major release. Use ' +
451+
'React.createContext() instead\n\n.' +
452+
'Learn more about this warning here: https://reactjs.org/link/legacy-context',
453+
name,
454+
);
455+
}
456+
if (
457+
ctor.contextTypes &&
458+
!didWarnAboutLegacyContext.has(ctor) &&
459+
// Strict Mode has its own warning for legacy context, so we can skip
460+
// this one.
461+
(workInProgress.mode & StrictLegacyMode) === NoMode
462+
) {
463+
didWarnAboutLegacyContext.add(ctor);
464+
console.error(
465+
'%s uses the legacy contextTypes API which is no longer supported ' +
466+
'and will be removed in the next major release. Use ' +
467+
'React.createContext() with static contextType instead.\n\n' +
468+
'Learn more about this warning here: https://reactjs.org/link/legacy-context',
469+
name,
470+
);
471+
}
472+
438473
if (instance.contextTypes) {
439474
console.error(
440475
'contextTypes was defined as an instance property on %s. Use a static ' +

packages/react-reconciler/src/ReactFiberClassComponent.old.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ let warnOnInvalidCallback;
9696
let didWarnAboutDirectlyAssigningPropsToState;
9797
let didWarnAboutContextTypeAndContextTypes;
9898
let didWarnAboutInvalidateContextType;
99+
let didWarnAboutLegacyContext;
99100

100101
if (__DEV__) {
101102
didWarnAboutStateAssignmentForComponent = new Set();
@@ -106,6 +107,7 @@ if (__DEV__) {
106107
didWarnAboutUndefinedDerivedState = new Set();
107108
didWarnAboutContextTypeAndContextTypes = new Set();
108109
didWarnAboutInvalidateContextType = new Set();
110+
didWarnAboutLegacyContext = new Set();
109111

110112
const didWarnOnInvalidCallback = new Set();
111113

@@ -435,6 +437,39 @@ function checkClassInstance(workInProgress: Fiber, ctor: any, newProps: any) {
435437
);
436438
}
437439
} else {
440+
if (
441+
ctor.childContextTypes &&
442+
!didWarnAboutLegacyContext.has(ctor) &&
443+
// Strict Mode has its own warning for legacy context, so we can skip
444+
// this one.
445+
(workInProgress.mode & StrictLegacyMode) === NoMode
446+
) {
447+
didWarnAboutLegacyContext.add(ctor);
448+
console.error(
449+
'%s uses the legacy childContextTypes API which is no longer ' +
450+
'supported and will be removed in the next major release. Use ' +
451+
'React.createContext() instead\n\n.' +
452+
'Learn more about this warning here: https://reactjs.org/link/legacy-context',
453+
name,
454+
);
455+
}
456+
if (
457+
ctor.contextTypes &&
458+
!didWarnAboutLegacyContext.has(ctor) &&
459+
// Strict Mode has its own warning for legacy context, so we can skip
460+
// this one.
461+
(workInProgress.mode & StrictLegacyMode) === NoMode
462+
) {
463+
didWarnAboutLegacyContext.add(ctor);
464+
console.error(
465+
'%s uses the legacy contextTypes API which is no longer supported ' +
466+
'and will be removed in the next major release. Use ' +
467+
'React.createContext() with static contextType instead.\n\n' +
468+
'Learn more about this warning here: https://reactjs.org/link/legacy-context',
469+
name,
470+
);
471+
}
472+
438473
if (instance.contextTypes) {
439474
console.error(
440475
'contextTypes was defined as an instance property on %s. Use a static ' +

0 commit comments

Comments
 (0)