unify deprecated/unsafe lifecycle warnings, pass tests (#16103)
- redoes #15431 from scratch, taking on the feedback there - unifies the messaging between "deprecated" and UNSAFE_ lifecycle messages. It reorganizes ReactStrictModeWarnings.js to capture and flush all the lifecycle warnings in one procedure each. - matches the warning from ReactPartialRenderer to match the above change - passes all the tests - this also turns on `warnAboutDeprecatedLifecycles` for the test renderer. I think we missed doing so it previously. In a future PR, I'll remove the feature flag altogether. - this DOES NOT do the same treatment for context warnings, I'll do that in another PR too
Sunil Pai committed
Jul 15, 2019 at 20:56 UTC
d9b4c55d53c67045c38b12f5aad57a163e7f63a2
16 files changed
+401
-361
packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js
+43
-27
@@ -709,9 +709,9 @@ describe('ReactComponentLifeCycle', () => {
709
);
710
}).toLowPriorityWarnDev(
711
[
712
- 'componentWillMount is deprecated',
713
- 'componentWillReceiveProps is deprecated',
714
- 'componentWillUpdate is deprecated',
712
+ 'componentWillMount has been renamed',
713
+ 'componentWillReceiveProps has been renamed',
714
+ 'componentWillUpdate has been renamed',
715
],
716
{withoutStack: true},
717
);
@@ -748,9 +748,9 @@ describe('ReactComponentLifeCycle', () => {
748
);
749
}).toLowPriorityWarnDev(
750
[
751
- 'componentWillMount is deprecated',
752
- 'componentWillReceiveProps is deprecated',
753
- 'componentWillUpdate is deprecated',
751
+ 'componentWillMount has been renamed',
752
+ 'componentWillReceiveProps has been renamed',
753
+ 'componentWillUpdate has been renamed',
754
],
755
{withoutStack: true},
756
);
@@ -815,7 +815,10 @@ describe('ReactComponentLifeCycle', () => {
815
{withoutStack: true},
816
);
817
}).toLowPriorityWarnDev(
818
- ['componentWillMount is deprecated', 'componentWillUpdate is deprecated'],
818
+ [
819
+ 'componentWillMount has been renamed',
820
+ 'componentWillUpdate has been renamed',
821
+ ],
822
{withoutStack: true},
823
);
824
@@ -863,7 +866,7 @@ describe('ReactComponentLifeCycle', () => {
866
'https://fb.me/react-async-component-lifecycle-hooks',
867
{withoutStack: true},
868
);
866
- }).toLowPriorityWarnDev(['componentWillMount is deprecated'], {
869
+ }).toLowPriorityWarnDev(['componentWillMount has been renamed'], {
870
withoutStack: true,
871
});
872
@@ -887,7 +890,7 @@ describe('ReactComponentLifeCycle', () => {
890
'https://fb.me/react-async-component-lifecycle-hooks',
891
{withoutStack: true},
892
);
890
- }).toLowPriorityWarnDev(['componentWillReceiveProps is deprecated'], {
893
+ }).toLowPriorityWarnDev(['componentWillReceiveProps has been renamed'], {
894
withoutStack: true,
895
});
896
});
@@ -921,7 +924,10 @@ describe('ReactComponentLifeCycle', () => {
924
{withoutStack: true},
925
);
926
}).toLowPriorityWarnDev(
924
- ['componentWillMount is deprecated', 'componentWillUpdate is deprecated'],
927
+ [
928
+ 'componentWillMount has been renamed',
929
+ 'componentWillUpdate has been renamed',
930
+ ],
931
{withoutStack: true},
932
);
933
@@ -967,7 +973,7 @@ describe('ReactComponentLifeCycle', () => {
973
'https://fb.me/react-async-component-lifecycle-hooks',
974
{withoutStack: true},
975
);
970
- }).toLowPriorityWarnDev(['componentWillMount is deprecated'], {
976
+ }).toLowPriorityWarnDev(['componentWillMount has been renamed'], {
977
withoutStack: true,
978
});
979
@@ -990,7 +996,7 @@ describe('ReactComponentLifeCycle', () => {
996
'https://fb.me/react-async-component-lifecycle-hooks',
997
{withoutStack: true},
998
);
993
- }).toLowPriorityWarnDev(['componentWillReceiveProps is deprecated'], {
999
+ }).toLowPriorityWarnDev(['componentWillReceiveProps has been renamed'], {
1000
withoutStack: true,
1001
});
1002
});
@@ -1130,9 +1136,9 @@ describe('ReactComponentLifeCycle', () => {
1136
ReactDOM.render(<MyComponent foo="bar" />, div),
1137
).toLowPriorityWarnDev(
1138
[
1133
- 'componentWillMount is deprecated',
1134
- 'componentWillReceiveProps is deprecated',
1135
- 'componentWillUpdate is deprecated',
1139
+ 'componentWillMount has been renamed',
1140
+ 'componentWillReceiveProps has been renamed',
1141
+ 'componentWillUpdate has been renamed',
1142
],
1143
{withoutStack: true},
1144
);
@@ -1403,22 +1409,32 @@ describe('ReactComponentLifeCycle', () => {
1409
ReactDOM.render(<MyComponent x={1} />, container),
1410
).toLowPriorityWarnDev(
1411
[
1406
- 'componentWillMount is deprecated and will be removed in the next major version. ' +
1407
- 'Use componentDidMount instead. As a temporary workaround, ' +
1408
- 'you can rename to UNSAFE_componentWillMount.' +
1409
- '\n\nPlease update the following components: MyComponent',
1410
- 'componentWillReceiveProps is deprecated and will be removed in the next major version. ' +
1411
- 'Use static getDerivedStateFromProps instead.' +
1412
- '\n\nPlease update the following components: MyComponent',
1413
- 'componentWillUpdate is deprecated and will be removed in the next major version. ' +
1414
- 'Use componentDidUpdate instead. As a temporary workaround, ' +
1415
- 'you can rename to UNSAFE_componentWillUpdate.' +
1416
- '\n\nPlease update the following components: MyComponent',
1412
+ /* eslint-disable max-len */
1413
+ `Warning: componentWillMount has been renamed, and is not recommended for use. See https://fb.me/react-async-component-lifecycle-hooks for details.
1414
+
1415
+* Move code with side effects to componentDidMount, and set initial state in the constructor.
1416
+* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run \`npx react-codemod rename-unsafe-lifecycles\` in your project source folder.
1417
+
1418
+Please update the following components: MyComponent`,
1419
+ `Warning: componentWillReceiveProps has been renamed, and is not recommended for use. See https://fb.me/react-async-component-lifecycle-hooks for details.
1420
+
1421
+* Move data fetching code or side effects to componentDidUpdate.
1422
+* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://fb.me/react-derived-state
1423
+* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run \`npx react-codemod rename-unsafe-lifecycles\` in your project source folder.
1424
+
1425
+Please update the following components: MyComponent`,
1426
+ `Warning: componentWillUpdate has been renamed, and is not recommended for use. See https://fb.me/react-async-component-lifecycle-hooks for details.
1427
+
1428
+* Move data fetching code or side effects to componentDidUpdate.
1429
+* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run \`npx react-codemod rename-unsafe-lifecycles\` in your project source folder.
1430
+
1431
+Please update the following components: MyComponent`,
1432
+ /* eslint-enable max-len */
1433
],
1434
{withoutStack: true},
1435
);
1436
1421
- // Dedupe check (update and instantiate new
1437
+ // Dedupe check (update and instantiate new)
1438
ReactDOM.render(<MyComponent x={2} />, container);
1439
ReactDOM.render(<MyComponent key="new" x={1} />, container);
1440
});
packages/react-dom/src/__tests__/ReactDOMServerLifecycles-test.js
+7
-10
@@ -229,7 +229,7 @@ describe('ReactDOMServerLifecycles', () => {
229
230
expect(() =>
231
ReactDOMServer.renderToString(<Component />),
232
- ).toLowPriorityWarnDev('componentWillMount() is deprecated', {
232
+ ).toLowPriorityWarnDev('componentWillMount has been renamed', {
233
withoutStack: true,
234
});
235
expect(log).toEqual(['componentWillMount', 'UNSAFE_componentWillMount']);
@@ -286,10 +286,9 @@ describe('ReactDOMServerLifecycles', () => {
286
287
expect(() =>
288
ReactDOMServer.renderToString(<Component />),
289
- ).toLowPriorityWarnDev(
290
- 'Component: componentWillMount() is deprecated and will be removed in the next major version.',
291
- {withoutStack: true},
292
- );
289
+ ).toLowPriorityWarnDev('componentWillMount has been renamed', {
290
+ withoutStack: true,
291
+ });
292
});
293
294
it('should warn about deprecated lifecycle hooks', () => {
@@ -302,11 +301,9 @@ describe('ReactDOMServerLifecycles', () => {
301
302
expect(() =>
303
ReactDOMServer.renderToString(<Component />),
305
- ).toLowPriorityWarnDev(
306
- 'Warning: Component: componentWillMount() is deprecated and will be removed ' +
307
- 'in the next major version.',
308
- {withoutStack: true},
309
- );
304
+ ).toLowPriorityWarnDev('componentWillMount has been renamed', {
305
+ withoutStack: true,
306
+ });
307
308
// De-duped
309
ReactDOMServer.renderToString(<Component />);
packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js
+7
-11
@@ -362,20 +362,16 @@ describe('ReactDOMServerHydration', () => {
362
const element = document.createElement('div');
363
expect(() => {
364
element.innerHTML = ReactDOMServer.renderToString(markup);
365
- }).toLowPriorityWarnDev(
366
- ['componentWillMount() is deprecated and will be removed'],
367
- {withoutStack: true},
368
- );
365
+ }).toLowPriorityWarnDev(['componentWillMount has been renamed'], {
366
+ withoutStack: true,
367
+ });
368
expect(element.textContent).toBe('Hi');
369
370
expect(() => {
372
- expect(() => ReactDOM.hydrate(markup, element)).toWarnDev(
373
- 'Please update the following components to use componentDidMount instead: ComponentWithWarning',
374
- );
375
- }).toLowPriorityWarnDev(
376
- ['componentWillMount is deprecated and will be removed'],
377
- {withoutStack: true},
378
- );
371
+ ReactDOM.hydrate(markup, element);
372
+ }).toLowPriorityWarnDev(['componentWillMount has been renamed'], {
373
+ withoutStack: true,
374
+ });
375
expect(element.textContent).toBe('Hi');
376
});
377
packages/react-dom/src/server/ReactPartialRenderer.js
+6
-7
@@ -572,13 +572,12 @@ function resolve(
572
if (!didWarnAboutDeprecatedWillMount[componentName]) {
573
lowPriorityWarning(
574
false,
575
- '%s: componentWillMount() is deprecated and will be ' +
576
- 'removed in the next major version. Read about the motivations ' +
577
- 'behind this change: ' +
578
- 'https://fb.me/react-async-component-lifecycle-hooks' +
579
- '\n\n' +
580
- 'As a temporary workaround, you can rename to ' +
581
- 'UNSAFE_componentWillMount instead.',
575
+ // keep this warning in sync with ReactStrictModeWarning.js
576
+ 'componentWillMount has been renamed, and is not recommended for use. ' +
577
+ 'See https://fb.me/react-async-component-lifecycle-hooks for details.\n\n' +
578
+ '* Move code from componentWillMount to componentDidMount (preferred in most cases) ' +
579
+ 'or the constructor.\n' +
580
+ '\nPlease update the following components: %s',
581
componentName,
582
);
583
didWarnAboutDeprecatedWillMount[componentName] = true;
packages/react-reconciler/src/ReactFiberClassComponent.js
+1
-6
@@ -806,11 +806,6 @@ function mountClassInstance(
806
}
807
808
if (workInProgress.mode & StrictMode) {
809
- ReactStrictModeWarnings.recordUnsafeLifecycleWarnings(
810
- workInProgress,
811
- instance,
812
- );
813
-
809
ReactStrictModeWarnings.recordLegacyContextWarning(
810
workInProgress,
811
instance,
@@ -818,7 +813,7 @@ function mountClassInstance(
813
}
814
815
if (warnAboutDeprecatedLifecycles) {
821
- ReactStrictModeWarnings.recordDeprecationWarnings(
816
+ ReactStrictModeWarnings.recordUnsafeLifecycleWarnings(
817
workInProgress,
818
instance,
819
);
packages/react-reconciler/src/ReactFiberWorkLoop.js
+1
-2
@@ -2247,11 +2247,10 @@ function checkForNestedUpdates() {
2247
2248
function flushRenderPhaseStrictModeWarningsInDEV() {
2249
if (__DEV__) {
2250
- ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings();
2250
ReactStrictModeWarnings.flushLegacyContextWarning();
2251
2252
if (warnAboutDeprecatedLifecycles) {
2254
- ReactStrictModeWarnings.flushPendingDeprecationWarnings();
2253
+ ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings();
2254
}
2255
}
2256
}
packages/react-reconciler/src/ReactStrictModeWarnings.js
+221
-213
@@ -16,105 +16,18 @@ import {StrictMode} from './ReactTypeOfMode';
16
import lowPriorityWarning from 'shared/lowPriorityWarning';
17
import warningWithoutStack from 'shared/warningWithoutStack';
18
19
-type LIFECYCLE =
20
- | 'UNSAFE_componentWillMount'
21
- | 'UNSAFE_componentWillReceiveProps'
22
- | 'UNSAFE_componentWillUpdate';
23
-type LifecycleToComponentsMap = {[lifecycle: LIFECYCLE]: Array<Fiber>};
24
-type FiberToLifecycleMap = Map<Fiber, LifecycleToComponentsMap>;
19
type FiberArray = Array<Fiber>;
20
type FiberToFiberComponentsMap = Map<Fiber, FiberArray>;
21
22
const ReactStrictModeWarnings = {
29
- discardPendingWarnings(): void {},
30
- flushPendingDeprecationWarnings(): void {},
31
- flushPendingUnsafeLifecycleWarnings(): void {},
32
- recordDeprecationWarnings(fiber: Fiber, instance: any): void {},
23
recordUnsafeLifecycleWarnings(fiber: Fiber, instance: any): void {},
24
+ flushPendingUnsafeLifecycleWarnings(): void {},
25
recordLegacyContextWarning(fiber: Fiber, instance: any): void {},
26
flushLegacyContextWarning(): void {},
27
+ discardPendingWarnings(): void {},
28
};
29
30
if (__DEV__) {
39
- const LIFECYCLE_SUGGESTIONS = {
40
- UNSAFE_componentWillMount: 'componentDidMount',
41
- UNSAFE_componentWillReceiveProps: 'static getDerivedStateFromProps',
42
- UNSAFE_componentWillUpdate: 'componentDidUpdate',
43
- };
44
-
45
- let pendingComponentWillMountWarnings: Array<Fiber> = [];
46
- let pendingComponentWillReceivePropsWarnings: Array<Fiber> = [];
47
- let pendingComponentWillUpdateWarnings: Array<Fiber> = [];
48
- let pendingUnsafeLifecycleWarnings: FiberToLifecycleMap = new Map();
49
- let pendingLegacyContextWarning: FiberToFiberComponentsMap = new Map();
50
-
51
- // Tracks components we have already warned about.
52
- const didWarnAboutDeprecatedLifecycles = new Set();
53
- const didWarnAboutUnsafeLifecycles = new Set();
54
- const didWarnAboutLegacyContext = new Set();
55
-
56
- const setToSortedString = set => {
57
- const array = [];
58
- set.forEach(value => {
59
- array.push(value);
60
- });
61
- return array.sort().join(', ');
62
- };
63
-
64
- ReactStrictModeWarnings.discardPendingWarnings = () => {
65
- pendingComponentWillMountWarnings = [];
66
- pendingComponentWillReceivePropsWarnings = [];
67
- pendingComponentWillUpdateWarnings = [];
68
- pendingUnsafeLifecycleWarnings = new Map();
69
- pendingLegacyContextWarning = new Map();
70
- };
71
-
72
- ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = () => {
73
- ((pendingUnsafeLifecycleWarnings: any): FiberToLifecycleMap).forEach(
74
- (lifecycleWarningsMap, strictRoot) => {
75
- const lifecyclesWarningMessages = [];
76
-
77
- Object.keys(lifecycleWarningsMap).forEach(lifecycle => {
78
- const lifecycleWarnings = lifecycleWarningsMap[lifecycle];
79
- if (lifecycleWarnings.length > 0) {
80
- const componentNames = new Set();
81
- lifecycleWarnings.forEach(fiber => {
82
- componentNames.add(getComponentName(fiber.type) || 'Component');
83
- didWarnAboutUnsafeLifecycles.add(fiber.type);
84
- });
85
-
86
- const formatted = lifecycle.replace('UNSAFE_', '');
87
- const suggestion = LIFECYCLE_SUGGESTIONS[lifecycle];
88
- const sortedComponentNames = setToSortedString(componentNames);
89
-
90
- lifecyclesWarningMessages.push(
91
- `${formatted}: Please update the following components to use ` +
92
- `${suggestion} instead: ${sortedComponentNames}`,
93
- );
94
- }
95
- });
96
-
97
- if (lifecyclesWarningMessages.length > 0) {
98
- const strictRootComponentStack = getStackByFiberInDevAndProd(
99
- strictRoot,
100
- );
101
-
102
- warningWithoutStack(
103
- false,
104
- 'Unsafe lifecycle methods were found within a strict-mode tree:%s' +
105
- '\n\n%s' +
106
- '\n\nLearn more about this warning here:' +
107
- '\nhttps://fb.me/react-strict-mode-warnings',
108
- strictRootComponentStack,
109
- lifecyclesWarningMessages.join('\n\n'),
110
- );
111
- }
112
- },
113
- );
114
-
115
- pendingUnsafeLifecycleWarnings = new Map();
116
- };
117
-
31
const findStrictRoot = (fiber: Fiber): Fiber | null => {
32
let maybeStrictRoot = null;
33
@@ -129,175 +42,260 @@ if (__DEV__) {
42
return maybeStrictRoot;
43
};
44
132
- ReactStrictModeWarnings.flushPendingDeprecationWarnings = () => {
133
- if (pendingComponentWillMountWarnings.length > 0) {
134
- const uniqueNames = new Set();
135
- pendingComponentWillMountWarnings.forEach(fiber => {
136
- uniqueNames.add(getComponentName(fiber.type) || 'Component');
137
- didWarnAboutDeprecatedLifecycles.add(fiber.type);
138
- });
139
-
140
- const sortedNames = setToSortedString(uniqueNames);
141
-
142
- lowPriorityWarning(
143
- false,
144
- 'componentWillMount is deprecated and will be removed in the next major version. ' +
145
- 'Use componentDidMount instead. As a temporary workaround, ' +
146
- 'you can rename to UNSAFE_componentWillMount.' +
147
- '\n\nPlease update the following components: %s' +
148
- '\n\nLearn more about this warning here:' +
149
- '\nhttps://fb.me/react-async-component-lifecycle-hooks',
150
- sortedNames,
151
- );
152
-
153
- pendingComponentWillMountWarnings = [];
154
- }
155
-
156
- if (pendingComponentWillReceivePropsWarnings.length > 0) {
157
- const uniqueNames = new Set();
158
- pendingComponentWillReceivePropsWarnings.forEach(fiber => {
159
- uniqueNames.add(getComponentName(fiber.type) || 'Component');
160
- didWarnAboutDeprecatedLifecycles.add(fiber.type);
161
- });
162
-
163
- const sortedNames = setToSortedString(uniqueNames);
164
-
165
- lowPriorityWarning(
166
- false,
167
- 'componentWillReceiveProps is deprecated and will be removed in the next major version. ' +
168
- 'Use static getDerivedStateFromProps instead.' +
169
- '\n\nPlease update the following components: %s' +
170
- '\n\nLearn more about this warning here:' +
171
- '\nhttps://fb.me/react-async-component-lifecycle-hooks',
172
- sortedNames,
173
- );
174
-
175
- pendingComponentWillReceivePropsWarnings = [];
176
- }
177
-
178
- if (pendingComponentWillUpdateWarnings.length > 0) {
179
- const uniqueNames = new Set();
180
- pendingComponentWillUpdateWarnings.forEach(fiber => {
181
- uniqueNames.add(getComponentName(fiber.type) || 'Component');
182
- didWarnAboutDeprecatedLifecycles.add(fiber.type);
183
- });
184
-
185
- const sortedNames = setToSortedString(uniqueNames);
45
+ const setToSortedString = set => {
46
+ const array = [];
47
+ set.forEach(value => {
48
+ array.push(value);
49
+ });
50
+ return array.sort().join(', ');
51
+ };
52
187
- lowPriorityWarning(
188
- false,
189
- 'componentWillUpdate is deprecated and will be removed in the next major version. ' +
190
- 'Use componentDidUpdate instead. As a temporary workaround, ' +
191
- 'you can rename to UNSAFE_componentWillUpdate.' +
192
- '\n\nPlease update the following components: %s' +
193
- '\n\nLearn more about this warning here:' +
194
- '\nhttps://fb.me/react-async-component-lifecycle-hooks',
195
- sortedNames,
196
- );
53
+ let pendingComponentWillMountWarnings: Array<Fiber> = [];
54
+ let pendingUNSAFE_ComponentWillMountWarnings: Array<Fiber> = [];
55
+ let pendingComponentWillReceivePropsWarnings: Array<Fiber> = [];
56
+ let pendingUNSAFE_ComponentWillReceivePropsWarnings: Array<Fiber> = [];
57
+ let pendingComponentWillUpdateWarnings: Array<Fiber> = [];
58
+ let pendingUNSAFE_ComponentWillUpdateWarnings: Array<Fiber> = [];
59
198
- pendingComponentWillUpdateWarnings = [];
199
- }
200
- };
60
+ // Tracks components we have already warned about.
61
+ const didWarnAboutUnsafeLifecycles = new Set();
62
202
- ReactStrictModeWarnings.recordDeprecationWarnings = (
63
+ ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = (
64
fiber: Fiber,
65
instance: any,
66
) => {
67
// Dedup strategy: Warn once per component.
207
- if (didWarnAboutDeprecatedLifecycles.has(fiber.type)) {
68
+ if (didWarnAboutUnsafeLifecycles.has(fiber.type)) {
69
return;
70
}
71
211
- // Don't warn about react-lifecycles-compat polyfilled components.
72
if (
73
typeof instance.componentWillMount === 'function' &&
74
+ // Don't warn about react-lifecycles-compat polyfilled components.
75
instance.componentWillMount.__suppressDeprecationWarning !== true
76
) {
77
pendingComponentWillMountWarnings.push(fiber);
78
}
79
+
80
+ if (
81
+ fiber.mode & StrictMode &&
82
+ typeof instance.UNSAFE_componentWillMount === 'function'
83
+ ) {
84
+ pendingUNSAFE_ComponentWillMountWarnings.push(fiber);
85
+ }
86
+
87
if (
88
typeof instance.componentWillReceiveProps === 'function' &&
89
instance.componentWillReceiveProps.__suppressDeprecationWarning !== true
90
) {
91
pendingComponentWillReceivePropsWarnings.push(fiber);
92
}
93
+
94
+ if (
95
+ fiber.mode & StrictMode &&
96
+ typeof instance.UNSAFE_componentWillReceiveProps === 'function'
97
+ ) {
98
+ pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber);
99
+ }
100
+
101
if (
102
typeof instance.componentWillUpdate === 'function' &&
103
instance.componentWillUpdate.__suppressDeprecationWarning !== true
104
) {
105
pendingComponentWillUpdateWarnings.push(fiber);
106
}
107
+
108
+ if (
109
+ fiber.mode & StrictMode &&
110
+ typeof instance.UNSAFE_componentWillUpdate === 'function'
111
+ ) {
112
+ pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber);
113
+ }
114
};
115
232
- ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = (
233
- fiber: Fiber,
234
- instance: any,
235
- ) => {
236
- const strictRoot = findStrictRoot(fiber);
237
- if (strictRoot === null) {
116
+ ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = () => {
117
+ // We do an initial pass to gather component names
118
+ const componentWillMountUniqueNames = new Set();
119
+ if (pendingComponentWillMountWarnings.length > 0) {
120
+ pendingComponentWillMountWarnings.forEach(fiber => {
121
+ componentWillMountUniqueNames.add(
122
+ getComponentName(fiber.type) || 'Component',
123
+ );
124
+ didWarnAboutUnsafeLifecycles.add(fiber.type);
125
+ });
126
+ pendingComponentWillMountWarnings = [];
127
+ }
128
+
129
+ const UNSAFE_componentWillMountUniqueNames = new Set();
130
+ if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) {
131
+ pendingUNSAFE_ComponentWillMountWarnings.forEach(fiber => {
132
+ UNSAFE_componentWillMountUniqueNames.add(
133
+ getComponentName(fiber.type) || 'Component',
134
+ );
135
+ didWarnAboutUnsafeLifecycles.add(fiber.type);
136
+ });
137
+ pendingUNSAFE_ComponentWillMountWarnings = [];
138
+ }
139
+
140
+ const componentWillReceivePropsUniqueNames = new Set();
141
+ if (pendingComponentWillReceivePropsWarnings.length > 0) {
142
+ pendingComponentWillReceivePropsWarnings.forEach(fiber => {
143
+ componentWillReceivePropsUniqueNames.add(
144
+ getComponentName(fiber.type) || 'Component',
145
+ );
146
+ didWarnAboutUnsafeLifecycles.add(fiber.type);
147
+ });
148
+
149
+ pendingComponentWillReceivePropsWarnings = [];
150
+ }
151
+
152
+ const UNSAFE_componentWillReceivePropsUniqueNames = new Set();
153
+ if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) {
154
+ pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach(fiber => {
155
+ UNSAFE_componentWillReceivePropsUniqueNames.add(
156
+ getComponentName(fiber.type) || 'Component',
157
+ );
158
+ didWarnAboutUnsafeLifecycles.add(fiber.type);
159
+ });
160
+
161
+ pendingUNSAFE_ComponentWillReceivePropsWarnings = [];
162
+ }
163
+
164
+ const componentWillUpdateUniqueNames = new Set();
165
+ if (pendingComponentWillUpdateWarnings.length > 0) {
166
+ pendingComponentWillUpdateWarnings.forEach(fiber => {
167
+ componentWillUpdateUniqueNames.add(
168
+ getComponentName(fiber.type) || 'Component',
169
+ );
170
+ didWarnAboutUnsafeLifecycles.add(fiber.type);
171
+ });
172
+
173
+ pendingComponentWillUpdateWarnings = [];
174
+ }
175
+
176
+ const UNSAFE_componentWillUpdateUniqueNames = new Set();
177
+ if (pendingUNSAFE_ComponentWillUpdateWarnings.length > 0) {
178
+ pendingUNSAFE_ComponentWillUpdateWarnings.forEach(fiber => {
179
+ UNSAFE_componentWillUpdateUniqueNames.add(
180
+ getComponentName(fiber.type) || 'Component',
181
+ );
182
+ didWarnAboutUnsafeLifecycles.add(fiber.type);
183
+ });
184
+
185
+ pendingUNSAFE_ComponentWillUpdateWarnings = [];
186
+ }
187
+
188
+ // Finally, we flush all the warnings
189
+ // UNSAFE_ ones before the deprecated ones, since they'll be 'louder'
190
+ if (UNSAFE_componentWillMountUniqueNames.size > 0) {
191
+ const sortedNames = setToSortedString(
192
+ UNSAFE_componentWillMountUniqueNames,
193
+ );
194
warningWithoutStack(
195
false,
240
- 'Expected to find a StrictMode component in a strict mode tree. ' +
241
- 'This error is likely caused by a bug in React. Please file an issue.',
196
+ 'Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. ' +
197
+ 'See https://fb.me/react-async-component-lifecycle-hooks for details.\n\n' +
198
+ '* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
199
+ '\nPlease update the following components: %s',
200
+ sortedNames,
201
);
243
- return;
202
}
203
246
- // Dedup strategy: Warn once per component.
247
- // This is difficult to track any other way since component names
248
- // are often vague and are likely to collide between 3rd party libraries.
249
- // An expand property is probably okay to use here since it's DEV-only,
250
- // and will only be set in the event of serious warnings.
251
- if (didWarnAboutUnsafeLifecycles.has(fiber.type)) {
252
- return;
204
+ if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) {
205
+ const sortedNames = setToSortedString(
206
+ UNSAFE_componentWillReceivePropsUniqueNames,
207
+ );
208
+ warningWithoutStack(
209
+ false,
210
+ 'Using UNSAFE_componentWillReceiveProps in strict mode is not recommended ' +
211
+ 'and may indicate bugs in your code. ' +
212
+ 'See https://fb.me/react-async-component-lifecycle-hooks for details.\n\n' +
213
+ '* Move data fetching code or side effects to componentDidUpdate.\n' +
214
+ "* If you're updating state whenever props change, " +
215
+ 'refactor your code to use memoization techniques or move it to ' +
216
+ 'static getDerivedStateFromProps. Learn more at: https://fb.me/react-derived-state\n' +
217
+ '\nPlease update the following components: %s',
218
+ sortedNames,
219
+ );
220
}
221
255
- let warningsForRoot;
256
- if (!pendingUnsafeLifecycleWarnings.has(strictRoot)) {
257
- warningsForRoot = {
258
- UNSAFE_componentWillMount: [],
259
- UNSAFE_componentWillReceiveProps: [],
260
- UNSAFE_componentWillUpdate: [],
261
- };
262
-
263
- pendingUnsafeLifecycleWarnings.set(strictRoot, warningsForRoot);
264
- } else {
265
- warningsForRoot = pendingUnsafeLifecycleWarnings.get(strictRoot);
222
+ if (UNSAFE_componentWillUpdateUniqueNames.size > 0) {
223
+ const sortedNames = setToSortedString(
224
+ UNSAFE_componentWillUpdateUniqueNames,
225
+ );
226
+ warningWithoutStack(
227
+ false,
228
+ 'Using UNSAFE_componentWillUpdate in strict mode is not recommended ' +
229
+ 'and may indicate bugs in your code. ' +
230
+ 'See https://fb.me/react-async-component-lifecycle-hooks for details.\n\n' +
231
+ '* Move data fetching code or side effects to componentDidUpdate.\n' +
232
+ '\nPlease update the following components: %s',
233
+ sortedNames,
234
+ );
235
}
236
268
- const unsafeLifecycles = [];
269
- if (
270
- (typeof instance.componentWillMount === 'function' &&
271
- instance.componentWillMount.__suppressDeprecationWarning !== true) ||
272
- typeof instance.UNSAFE_componentWillMount === 'function'
273
- ) {
274
- unsafeLifecycles.push('UNSAFE_componentWillMount');
275
- }
276
- if (
277
- (typeof instance.componentWillReceiveProps === 'function' &&
278
- instance.componentWillReceiveProps.__suppressDeprecationWarning !==
279
- true) ||
280
- typeof instance.UNSAFE_componentWillReceiveProps === 'function'
281
- ) {
282
- unsafeLifecycles.push('UNSAFE_componentWillReceiveProps');
237
+ if (componentWillMountUniqueNames.size > 0) {
238
+ const sortedNames = setToSortedString(componentWillMountUniqueNames);
239
+
240
+ lowPriorityWarning(
241
+ false,
242
+ 'componentWillMount has been renamed, and is not recommended for use. ' +
243
+ 'See https://fb.me/react-async-component-lifecycle-hooks for details.\n\n' +
244
+ '* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
245
+ '* Rename componentWillMount to UNSAFE_componentWillMount to suppress ' +
246
+ 'this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. ' +
247
+ 'To rename all deprecated lifecycles to their new names, you can run ' +
248
+ '`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
249
+ '\nPlease update the following components: %s',
250
+ sortedNames,
251
+ );
252
}
284
- if (
285
- (typeof instance.componentWillUpdate === 'function' &&
286
- instance.componentWillUpdate.__suppressDeprecationWarning !== true) ||
287
- typeof instance.UNSAFE_componentWillUpdate === 'function'
288
- ) {
289
- unsafeLifecycles.push('UNSAFE_componentWillUpdate');
253
+
254
+ if (componentWillReceivePropsUniqueNames.size > 0) {
255
+ const sortedNames = setToSortedString(
256
+ componentWillReceivePropsUniqueNames,
257
+ );
258
+
259
+ lowPriorityWarning(
260
+ false,
261
+ 'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
262
+ 'See https://fb.me/react-async-component-lifecycle-hooks for details.\n\n' +
263
+ '* Move data fetching code or side effects to componentDidUpdate.\n' +
264
+ "* If you're updating state whenever props change, refactor your " +
265
+ 'code to use memoization techniques or move it to ' +
266
+ 'static getDerivedStateFromProps. Learn more at: https://fb.me/react-derived-state\n' +
267
+ '* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress ' +
268
+ 'this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. ' +
269
+ 'To rename all deprecated lifecycles to their new names, you can run ' +
270
+ '`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
271
+ '\nPlease update the following components: %s',
272
+ sortedNames,
273
+ );
274
}
275
292
- if (unsafeLifecycles.length > 0) {
293
- unsafeLifecycles.forEach(lifecycle => {
294
- ((warningsForRoot: any): LifecycleToComponentsMap)[lifecycle].push(
295
- fiber,
296
- );
297
- });
276
+ if (componentWillUpdateUniqueNames.size > 0) {
277
+ const sortedNames = setToSortedString(componentWillUpdateUniqueNames);
278
+
279
+ lowPriorityWarning(
280
+ false,
281
+ 'componentWillUpdate has been renamed, and is not recommended for use. ' +
282
+ 'See https://fb.me/react-async-component-lifecycle-hooks for details.\n\n' +
283
+ '* Move data fetching code or side effects to componentDidUpdate.\n' +
284
+ '* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress ' +
285
+ 'this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. ' +
286
+ 'To rename all deprecated lifecycles to their new names, you can run ' +
287
+ '`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
288
+ '\nPlease update the following components: %s',
289
+ sortedNames,
290
+ );
291
}
292
};
293
294
+ let pendingLegacyContextWarning: FiberToFiberComponentsMap = new Map();
295
+
296
+ // Tracks components we have already warned about.
297
+ const didWarnAboutLegacyContext = new Set();
298
+
299
ReactStrictModeWarnings.recordLegacyContextWarning = (
300
fiber: Fiber,
301
instance: any,
@@ -358,6 +356,16 @@ if (__DEV__) {
356
},
357
);
358
};
359
+
360
+ ReactStrictModeWarnings.discardPendingWarnings = () => {
361
+ pendingComponentWillMountWarnings = [];
362
+ pendingUNSAFE_ComponentWillMountWarnings = [];
363
+ pendingComponentWillReceivePropsWarnings = [];
364
+ pendingUNSAFE_ComponentWillReceivePropsWarnings = [];
365
+ pendingComponentWillUpdateWarnings = [];
366
+ pendingUNSAFE_ComponentWillUpdateWarnings = [];
367
+ pendingLegacyContextWarning = new Map();
368
+ };
369
}
370
371
export default ReactStrictModeWarnings;
packages/react-reconciler/src/__tests__/ReactIncremental-test.internal.js
+14
-5
@@ -2446,8 +2446,7 @@ describe('ReactIncremental', () => {
2446
ReactNoop.render(<MyComponent />);
2447
expect(() => expect(Scheduler).toFlushWithoutYielding()).toWarnDev(
2448
[
2449
- 'componentWillReceiveProps: Please update the following components ' +
2450
- 'to use static getDerivedStateFromProps instead: MyComponent',
2449
+ 'Using UNSAFE_componentWillReceiveProps in strict mode is not recommended',
2450
'Legacy context API has been detected within a strict-mode tree: \n\n' +
2451
'Please update the following components: MyComponent',
2452
],
@@ -2887,8 +2886,7 @@ describe('ReactIncremental', () => {
2886
expect(Scheduler).toFlushAndYield([]);
2887
});
2888
2890
- // We don't currently use fibers as keys. Re-enable this test if we
2891
- // ever do again.
2889
+ // We sometimes use Maps with Fibers as keys.
2890
it('does not break with a bad Map polyfill', () => {
2891
const realMapSet = Map.prototype.set;
2892
@@ -2896,17 +2894,27 @@ describe('ReactIncremental', () => {
2894
function Thing() {
2895
throw new Error('No.');
2896
}
2897
+ // This class uses legacy context, which triggers warnings,
2898
+ // the procedures for which use a Map to store fibers.
2899
class Boundary extends React.Component {
2900
state = {didError: false};
2901
componentDidCatch() {
2902
this.setState({didError: true});
2903
}
2904
+ static contextTypes = {
2905
+ color: () => null,
2906
+ };
2907
render() {
2908
return this.state.didError ? null : <Thing />;
2909
}
2910
}
2911
ReactNoop.render(<Boundary />);
2909
- expect(Scheduler).toFlushWithoutYielding();
2912
+ expect(() => {
2913
+ expect(Scheduler).toFlushWithoutYielding();
2914
+ }).toWarnDev(
2915
+ ['Legacy context API has been detected within a strict-mode tree'],
2916
+ {withoutStack: true},
2917
+ );
2918
}
2919
2920
// First, verify that this code path normally receives Fibers as keys,
@@ -2952,6 +2960,7 @@ describe('ReactIncremental', () => {
2960
};
2961
React = require('react');
2962
ReactNoop = require('react-noop-renderer');
2963
+ Scheduler = require('scheduler');
2964
try {
2965
triggerCodePathThatUsesFibersAsMapKeys();
2966
} finally {
packages/react-reconciler/src/__tests__/ReactIncrementalPerf-test.internal.js
+6
-12
@@ -316,10 +316,8 @@ describe('ReactDebugFiberPerf', () => {
316
addComment('Should not print a warning');
317
expect(() => expect(Scheduler).toFlushWithoutYielding()).toWarnDev(
318
[
319
- 'componentWillMount: Please update the following components ' +
320
- 'to use componentDidMount instead: NotCascading' +
321
- '\n\ncomponentWillReceiveProps: Please update the following components ' +
322
- 'to use static getDerivedStateFromProps instead: NotCascading',
319
+ 'Using UNSAFE_componentWillMount in strict mode is not recommended',
320
+ 'Using UNSAFE_componentWillReceiveProps in strict mode is not recommended',
321
],
322
{withoutStack: true},
323
);
@@ -358,14 +356,10 @@ describe('ReactDebugFiberPerf', () => {
356
addComment('Mount');
357
expect(() => expect(Scheduler).toFlushWithoutYielding()).toWarnDev(
358
[
361
- 'componentWillMount: Please update the following components ' +
362
- 'to use componentDidMount instead: AllLifecycles' +
363
- '\n\ncomponentWillReceiveProps: Please update the following components ' +
364
- 'to use static getDerivedStateFromProps instead: AllLifecycles' +
365
- '\n\ncomponentWillUpdate: Please update the following components ' +
366
- 'to use componentDidUpdate instead: AllLifecycles',
367
- 'Legacy context API has been detected within a strict-mode tree: \n\n' +
368
- 'Please update the following components: AllLifecycles',
359
+ 'Using UNSAFE_componentWillMount in strict mode is not recommended',
360
+ 'Using UNSAFE_componentWillReceiveProps in strict mode is not recommended',
361
+ 'Using UNSAFE_componentWillUpdate in strict mode is not recommended',
362
+ 'Legacy context API has been detected within a strict-mode tree',
363
],
364
{withoutStack: true},
365
);
packages/react-reconciler/src/__tests__/ReactIncrementalReflection-test.internal.js
+6
-8
@@ -76,8 +76,7 @@ describe('ReactIncrementalReflection', () => {
76
expect(() =>
77
expect(Scheduler).toFlushAndYield(['componentDidMount: true']),
78
).toWarnDev(
79
- 'componentWillMount: Please update the following components ' +
80
- 'to use componentDidMount instead: Component',
79
+ 'Using UNSAFE_componentWillMount in strict mode is not recommended',
80
{withoutStack: true},
81
);
82
@@ -116,8 +115,7 @@ describe('ReactIncrementalReflection', () => {
115
116
ReactNoop.render(<Foo mount={true} />);
117
expect(() => expect(Scheduler).toFlushAndYield(['Component'])).toWarnDev(
119
- 'componentWillMount: Please update the following components ' +
120
- 'to use componentDidMount instead: Component',
118
+ 'Using UNSAFE_componentWillMount in strict mode is not recommended',
119
{withoutStack: true},
120
);
121
@@ -222,10 +220,10 @@ describe('ReactIncrementalReflection', () => {
220
expect(() =>
221
expect(Scheduler).toFlushAndYield([['componentDidMount', span()]]),
222
).toWarnDev(
225
- 'componentWillMount: Please update the following components ' +
226
- 'to use componentDidMount instead: Component' +
227
- '\n\ncomponentWillUpdate: Please update the following components ' +
228
- 'to use componentDidUpdate instead: Component',
223
+ [
224
+ 'Using UNSAFE_componentWillMount in strict mode is not recommended',
225
+ 'Using UNSAFE_componentWillUpdate in strict mode is not recommended',
226
+ ],
227
{withoutStack: true},
228
);
229
packages/react-reconciler/src/__tests__/ReactIncrementalUpdates-test.internal.js
+1
-2
@@ -346,8 +346,7 @@ describe('ReactIncrementalUpdates', () => {
346
}
347
ReactNoop.render(<Foo />);
348
expect(() => expect(Scheduler).toFlushWithoutYielding()).toWarnDev(
349
- 'componentWillReceiveProps: Please update the following components ' +
350
- 'to use static getDerivedStateFromProps instead: Foo',
349
+ 'Using UNSAFE_componentWillReceiveProps in strict mode is not recommended',
350
{withoutStack: true},
351
);
352
packages/react/src/__tests__/ReactStrictMode-test.internal.js
+65
-39
@@ -349,15 +349,26 @@ describe('ReactStrictMode', () => {
349
});
350
root.update(<AsyncRoot />);
351
expect(() => Scheduler.unstable_flushAll()).toWarnDev(
352
- 'Unsafe lifecycle methods were found within a strict-mode tree:' +
353
- '\n\ncomponentWillMount: Please update the following components ' +
354
- 'to use componentDidMount instead: AsyncRoot' +
355
- '\n\ncomponentWillReceiveProps: Please update the following components ' +
356
- 'to use static getDerivedStateFromProps instead: Bar, Foo' +
357
- '\n\ncomponentWillUpdate: Please update the following components ' +
358
- 'to use componentDidUpdate instead: AsyncRoot' +
359
- '\n\nLearn more about this warning here:' +
360
- '\nhttps://fb.me/react-strict-mode-warnings',
352
+ [
353
+ /* eslint-disable max-len */
354
+ `Warning: Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. See https://fb.me/react-async-component-lifecycle-hooks for details.
355
+
356
+* Move code with side effects to componentDidMount, and set initial state in the constructor.
357
+
358
+Please update the following components: AsyncRoot`,
359
+ `Warning: Using UNSAFE_componentWillReceiveProps in strict mode is not recommended and may indicate bugs in your code. See https://fb.me/react-async-component-lifecycle-hooks for details.
360
+
361
+* Move data fetching code or side effects to componentDidUpdate.
362
+* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://fb.me/react-derived-state
363
+
364
+Please update the following components: Bar, Foo`,
365
+ `Warning: Using UNSAFE_componentWillUpdate in strict mode is not recommended and may indicate bugs in your code. See https://fb.me/react-async-component-lifecycle-hooks for details.
366
+
367
+* Move data fetching code or side effects to componentDidUpdate.
368
+
369
+Please update the following components: AsyncRoot`,
370
+ /* eslint-enable max-len */
371
+ ],
372
{withoutStack: true},
373
);
374
@@ -396,26 +407,54 @@ describe('ReactStrictMode', () => {
407
408
expect(() => {
409
expect(() => Scheduler.unstable_flushAll()).toWarnDev(
399
- 'Unsafe lifecycle methods were found within a strict-mode tree:' +
400
- '\n\ncomponentWillMount: Please update the following components ' +
401
- 'to use componentDidMount instead: AsyncRoot, Parent' +
402
- '\n\ncomponentWillReceiveProps: Please update the following components ' +
403
- 'to use static getDerivedStateFromProps instead: Child, Parent' +
404
- '\n\ncomponentWillUpdate: Please update the following components ' +
405
- 'to use componentDidUpdate instead: AsyncRoot, Parent' +
406
- '\n\nLearn more about this warning here:' +
407
- '\nhttps://fb.me/react-strict-mode-warnings',
410
+ [
411
+ /* eslint-disable max-len */
412
+ `Warning: Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. See https://fb.me/react-async-component-lifecycle-hooks for details.
413
+
414
+* Move code with side effects to componentDidMount, and set initial state in the constructor.
415
+
416
+Please update the following components: AsyncRoot`,
417
+ `Warning: Using UNSAFE_componentWillReceiveProps in strict mode is not recommended and may indicate bugs in your code. See https://fb.me/react-async-component-lifecycle-hooks for details.
418
+
419
+* Move data fetching code or side effects to componentDidUpdate.
420
+* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://fb.me/react-derived-state
421
+
422
+Please update the following components: Child`,
423
+ `Warning: Using UNSAFE_componentWillUpdate in strict mode is not recommended and may indicate bugs in your code. See https://fb.me/react-async-component-lifecycle-hooks for details.
424
+
425
+* Move data fetching code or side effects to componentDidUpdate.
426
+
427
+Please update the following components: AsyncRoot`,
428
+ /* eslint-enable max-len */
429
+ ],
430
{withoutStack: true},
431
);
432
}).toLowPriorityWarnDev(
433
[
412
- 'componentWillMount is deprecated',
413
- 'componentWillReceiveProps is deprecated',
414
- 'componentWillUpdate is deprecated',
434
+ /* eslint-disable max-len */
435
+ `Warning: componentWillMount has been renamed, and is not recommended for use. See https://fb.me/react-async-component-lifecycle-hooks for details.
436
+
437
+* Move code with side effects to componentDidMount, and set initial state in the constructor.
438
+* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run \`npx react-codemod rename-unsafe-lifecycles\` in your project source folder.
439
+
440
+Please update the following components: Parent`,
441
+ `Warning: componentWillReceiveProps has been renamed, and is not recommended for use. See https://fb.me/react-async-component-lifecycle-hooks for details.
442
+
443
+* Move data fetching code or side effects to componentDidUpdate.
444
+* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://fb.me/react-derived-state
445
+* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run \`npx react-codemod rename-unsafe-lifecycles\` in your project source folder.
446
+
447
+Please update the following components: Parent`,
448
+ `Warning: componentWillUpdate has been renamed, and is not recommended for use. See https://fb.me/react-async-component-lifecycle-hooks for details.
449
+
450
+* Move data fetching code or side effects to componentDidUpdate.
451
+* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run \`npx react-codemod rename-unsafe-lifecycles\` in your project source folder.
452
+
453
+Please update the following components: Parent`,
454
+ /* eslint-enable max-len */
455
],
456
{withoutStack: true},
457
);
418
-
458
// Dedupe
459
root.update(<AsyncRoot />);
460
Scheduler.unstable_flushAll();
@@ -445,21 +484,13 @@ describe('ReactStrictMode', () => {
484
});
485
root.update(<AsyncRoot foo={true} />);
486
expect(() => Scheduler.unstable_flushAll()).toWarnDev(
448
- 'Unsafe lifecycle methods were found within a strict-mode tree:' +
449
- '\n\ncomponentWillMount: Please update the following components ' +
450
- 'to use componentDidMount instead: Foo' +
451
- '\n\nLearn more about this warning here:' +
452
- '\nhttps://fb.me/react-strict-mode-warnings',
487
+ 'Using UNSAFE_componentWillMount in strict mode is not recommended',
488
{withoutStack: true},
489
);
490
491
root.update(<AsyncRoot foo={false} />);
492
expect(() => Scheduler.unstable_flushAll()).toWarnDev(
458
- 'Unsafe lifecycle methods were found within a strict-mode tree:' +
459
- '\n\ncomponentWillMount: Please update the following components ' +
460
- 'to use componentDidMount instead: Bar' +
461
- '\n\nLearn more about this warning here:' +
462
- '\nhttps://fb.me/react-strict-mode-warnings',
493
+ 'Using UNSAFE_componentWillMount in strict mode is not recommended',
494
{withoutStack: true},
495
);
496
@@ -507,13 +538,8 @@ describe('ReactStrictMode', () => {
538
}
539
540
expect(() => ReactTestRenderer.create(<SyncRoot />)).toWarnDev(
510
- 'Unsafe lifecycle methods were found within a strict-mode tree:' +
511
- '\n in StrictMode (at **)' +
512
- '\n in SyncRoot (at **)' +
513
- '\n\ncomponentWillReceiveProps: Please update the following components ' +
514
- 'to use static getDerivedStateFromProps instead: Bar, Foo' +
515
- '\n\nLearn more about this warning here:' +
516
- '\nhttps://fb.me/react-strict-mode-warnings',
541
+ 'Using UNSAFE_componentWillReceiveProps in strict mode is not recommended',
542
+ {withoutStack: true},
543
);
544
545
// Dedupe
packages/react/src/__tests__/createReactClassIntegration-test.internal.js
+2
-7
@@ -51,10 +51,7 @@ describe('create-react-class-integration', () => {
51
});
52
53
expect(() => ReactNative.render(<View />, 1)).toLowPriorityWarnDev(
54
- 'componentWillMount is deprecated and will be removed in the next major version. ' +
55
- 'Use componentDidMount instead. As a temporary workaround, ' +
56
- 'you can rename to UNSAFE_componentWillMount.' +
57
- '\n\nPlease update the following components: MyNativeComponent',
54
+ 'componentWillMount has been renamed',
55
{withoutStack: true},
56
);
57
});
@@ -68,9 +65,7 @@ describe('create-react-class-integration', () => {
65
});
66
67
expect(() => ReactNative.render(<View />, 1)).toLowPriorityWarnDev(
71
- 'componentWillReceiveProps is deprecated and will be removed in the next major version. ' +
72
- 'Use static getDerivedStateFromProps instead.' +
73
- '\n\nPlease update the following components: MyNativeComponent',
68
+ 'componentWillReceiveProps has been renamed',
69
{withoutStack: true},
70
);
71
});
packages/react/src/__tests__/createReactClassIntegration-test.js
+9
-9
@@ -560,9 +560,9 @@ describe('create-react-class-integration', () => {
560
);
561
}).toLowPriorityWarnDev(
562
[
563
- 'componentWillMount is deprecated',
564
- 'componentWillReceiveProps is deprecated',
565
- 'componentWillUpdate is deprecated',
563
+ 'componentWillMount has been renamed',
564
+ 'componentWillReceiveProps has been renamed',
565
+ 'componentWillUpdate has been renamed',
566
],
567
{withoutStack: true},
568
);
@@ -604,9 +604,9 @@ describe('create-react-class-integration', () => {
604
);
605
}).toLowPriorityWarnDev(
606
[
607
- 'componentWillMount is deprecated',
608
- 'componentWillReceiveProps is deprecated',
609
- 'componentWillUpdate is deprecated',
607
+ 'componentWillMount has been renamed',
608
+ 'componentWillReceiveProps has been renamed',
609
+ 'componentWillUpdate has been renamed',
610
],
611
{withoutStack: true},
612
);
@@ -649,9 +649,9 @@ describe('create-react-class-integration', () => {
649
ReactDOM.render(<Component foo="bar" />, div),
650
).toLowPriorityWarnDev(
651
[
652
- 'componentWillMount is deprecated',
653
- 'componentWillReceiveProps is deprecated',
654
- 'componentWillUpdate is deprecated',
652
+ 'componentWillMount has been renamed',
653
+ 'componentWillReceiveProps has been renamed',
654
+ 'componentWillUpdate has been renamed',
655
],
656
{withoutStack: true},
657
);
packages/shared/forks/ReactFeatureFlags.test-renderer.js
+1
-1
@@ -15,7 +15,7 @@ import typeof * as PersistentFeatureFlagsType from './ReactFeatureFlags.persiste
15
export const debugRenderPhaseSideEffects = false;
16
export const debugRenderPhaseSideEffectsForStrictMode = false;
17
export const enableUserTimingAPI = __DEV__;
18
-export const warnAboutDeprecatedLifecycles = false;
18
+export const warnAboutDeprecatedLifecycles = true;
19
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
20
export const enableProfilerTimer = false;
21
export const enableSchedulerTracing = false;
scripts/print-warnings/print-warnings.js
+11
-2
@@ -52,8 +52,17 @@ function transform(file, enc, cb) {
52
53
// warning messages can be concatenated (`+`) at runtime, so here's
54
// a trivial partial evaluator that interprets the literal value
55
- const warningMsgLiteral = evalToString(node.arguments[1]);
56
- warnings.add(JSON.stringify(warningMsgLiteral));
55
+ try {
56
+ const warningMsgLiteral = evalToString(node.arguments[1]);
57
+ warnings.add(JSON.stringify(warningMsgLiteral));
58
+ } catch (error) {
59
+ console.error(
60
+ 'Failed to extract warning message from',
61
+ file.path
62
+ );
63
+ console.error(astPath.node.loc);
64
+ throw error;
65
+ }
66
}
67
},
68
},