@samitouri / QOS-React-2 / commits / d9b4c55d53

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 },