From 294effdcbd9e34d26126b77d3eec2149af5f1dfd Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Tue, 21 Jan 2020 17:01:54 +0000 Subject: [PATCH] Update legacy context warning --- .../src/ReactStrictModeWarnings.js | 40 ++++++--- .../ReactIncremental-test.internal.js | 87 ++++++------------- ...tIncrementalErrorHandling-test.internal.js | 32 +++---- .../ReactIncrementalPerf-test.internal.js | 2 +- .../ReactNewContext-test.internal.js | 3 +- .../src/__tests__/ReactStrictMode-test.js | 5 +- 6 files changed, 75 insertions(+), 94 deletions(-) diff --git a/packages/react-reconciler/src/ReactStrictModeWarnings.js b/packages/react-reconciler/src/ReactStrictModeWarnings.js index 29af663d90ec6..4ace418c233da 100644 --- a/packages/react-reconciler/src/ReactStrictModeWarnings.js +++ b/packages/react-reconciler/src/ReactStrictModeWarnings.js @@ -287,7 +287,6 @@ if (__DEV__) { // Tracks components we have already warned about. const didWarnAboutLegacyContext = new Set(); - ReactStrictModeWarnings.recordLegacyContextWarning = ( fiber: Fiber, instance: any, @@ -305,7 +304,6 @@ if (__DEV__) { if (didWarnAboutLegacyContext.has(fiber.type)) { return; } - let warningsForRoot = pendingLegacyContextWarning.get(strictRoot); if ( @@ -324,26 +322,46 @@ if (__DEV__) { ReactStrictModeWarnings.flushLegacyContextWarning = () => { ((pendingLegacyContextWarning: any): FiberToFiberComponentsMap).forEach( (fiberArray: FiberArray, strictRoot) => { - const uniqueNames = new Set(); + const componentStacks = new Map(); + fiberArray.forEach(fiber => { - uniqueNames.add(getComponentName(fiber.type) || 'Component'); + const componentName = getComponentName(fiber.type) || 'Component'; + const componentStack = getStackByFiberInDevAndProd(fiber); + let count = 0; + if (componentStacks.has(componentStack)) { + ({count} = componentStacks.get(componentStack)); + } + // Increase count by 1 + componentStacks.set(componentStack, { + count: count + 1, + name: componentName, + }); didWarnAboutLegacyContext.add(fiber.type); }); - const sortedNames = setToSortedString(uniqueNames); - const strictRootComponentStack = getStackByFiberInDevAndProd( - strictRoot, - ); + const stacks = Array.from(componentStacks.keys()); + // Find the most frequently found component stack and use that + let currentCount = 0; + let mostFrequentStack = null; + + for (let i = 0; i < stacks.length; i++) { + const stack = stacks[i]; + let {count} = componentStacks.get(stack); + if (count > currentCount || mostFrequentStack === null) { + currentCount = count; + mostFrequentStack = stack; + } + } console.error( 'Legacy context API has been detected within a strict-mode tree.' + '\n\nThe old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.' + - '\n\nPlease update the following components: %s' + + '\n\nPlease update the following component: %s' + '\n\nLearn more about this warning here: https://fb.me/react-legacy-context' + '%s', - sortedNames, - strictRootComponentStack, + componentStacks.get(mostFrequentStack).name, + mostFrequentStack, ); }, ); diff --git a/packages/react-reconciler/src/__tests__/ReactIncremental-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncremental-test.internal.js index e39b055f79c5f..c20c2e573294a 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncremental-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactIncremental-test.internal.js @@ -1916,8 +1916,7 @@ describe('ReactIncremental', () => { 'Legacy context API has been detected within a strict-mode tree.\n\n' + 'The old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.\n\n' + - 'Please update the following components: Intl, ShowBoth, ShowLocale', - {withoutStack: true}, + 'Please update the following component: Intl', ); ReactNoop.render( @@ -1973,8 +1972,7 @@ describe('ReactIncremental', () => { 'Legacy context API has been detected within a strict-mode tree.\n\n' + 'The old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.\n\n' + - 'Please update the following components: Router, ShowRoute', - {withoutStack: true}, + 'Please update the following component: Router', ); }); @@ -2000,14 +1998,11 @@ describe('ReactIncremental', () => { } ReactNoop.render(); - expect(() => - expect(Scheduler).toFlushWithoutYielding(), - ).toErrorDev( + expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev( 'Legacy context API has been detected within a strict-mode tree.\n\n' + 'The old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.\n\n' + - 'Please update the following components: Recurse', - {withoutStack: true}, + 'Please update the following component: Recurse', ); expect(ops).toEqual([ 'Recurse {}', @@ -2051,9 +2046,9 @@ describe('ReactIncremental', () => { 'Legacy context API has been detected within a strict-mode tree.\n\n' + 'The old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.\n\n' + - 'Please update the following components: Recurse', + 'Please update the following component: Recurse', ], - {withoutStack: 1}, + {withoutStack: 0}, ); expect(ops).toEqual([ 'Recurse {}', @@ -2119,8 +2114,7 @@ describe('ReactIncremental', () => { 'Legacy context API has been detected within a strict-mode tree.\n\n' + 'The old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.\n\n' + - 'Please update the following components: Intl, ShowLocale', - {withoutStack: true}, + 'Please update the following component: Intl', ); }); @@ -2196,14 +2190,11 @@ describe('ReactIncremental', () => { , ); - expect(() => - expect(Scheduler).toFlushWithoutYielding(), - ).toErrorDev( + expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev( 'Legacy context API has been detected within a strict-mode tree.\n\n' + 'The old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.\n\n' + - 'Please update the following components: Intl, ShowLocaleClass, ShowLocaleFn', - {withoutStack: true}, + 'Please update the following component: Intl', ); expect(ops).toEqual([ 'Intl:read {}', @@ -2292,14 +2283,11 @@ describe('ReactIncremental', () => { , ); - expect(() => - expect(Scheduler).toFlushWithoutYielding(), - ).toErrorDev( + expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev( 'Legacy context API has been detected within a strict-mode tree.\n\n' + 'The old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.\n\n' + - 'Please update the following components: Intl, ShowLocaleClass, ShowLocaleFn', - {withoutStack: true}, + 'Please update the following component: Intl', ); expect(ops).toEqual([ 'Intl:read {}', @@ -2365,14 +2353,11 @@ describe('ReactIncremental', () => { // Init ReactNoop.render(); - expect(() => - expect(Scheduler).toFlushWithoutYielding(), - ).toErrorDev( + expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev( 'Legacy context API has been detected within a strict-mode tree.\n\n' + 'The old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.\n\n' + - 'Please update the following components: Child', - {withoutStack: true}, + 'Please update the following component: Child', ); // Trigger an update in the middle of the tree @@ -2419,14 +2404,11 @@ describe('ReactIncremental', () => { // Init ReactNoop.render(); - expect(() => - expect(Scheduler).toFlushWithoutYielding(), - ).toErrorDev( + expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev( 'Legacy context API has been detected within a strict-mode tree.\n\n' + 'The old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.\n\n' + - 'Please update the following components: ContextProvider', - {withoutStack: true}, + 'Please update the following component: ContextProvider', ); // Trigger an update in the middle of the tree @@ -2477,9 +2459,9 @@ describe('ReactIncremental', () => { 'Legacy context API has been detected within a strict-mode tree.\n\n' + 'The old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.\n\n' + - 'Please update the following components: MyComponent', + 'Please update the following component: MyComponent', ], - {withoutStack: true}, + {withoutStack: 1}, ); expect(ops).toEqual([ @@ -2622,14 +2604,11 @@ describe('ReactIncremental', () => { , ); - expect(() => - expect(Scheduler).toFlushWithoutYielding(), - ).toErrorDev( + expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev( 'Legacy context API has been detected within a strict-mode tree.\n\n' + 'The old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.\n\n' + - 'Please update the following components: Child, TopContextProvider', - {withoutStack: true}, + 'Please update the following component: TopContextProvider', ); expect(rendered).toEqual(['count:0']); instance.updateCount(); @@ -2688,14 +2667,11 @@ describe('ReactIncremental', () => { , ); - expect(() => - expect(Scheduler).toFlushWithoutYielding(), - ).toErrorDev( + expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev( 'Legacy context API has been detected within a strict-mode tree.\n\n' + 'The old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.\n\n' + - 'Please update the following components: Child, MiddleContextProvider, TopContextProvider', - {withoutStack: true}, + 'Please update the following component: TopContextProvider', ); expect(rendered).toEqual(['count:0']); instance.updateCount(); @@ -2763,14 +2739,11 @@ describe('ReactIncremental', () => { , ); - expect(() => - expect(Scheduler).toFlushWithoutYielding(), - ).toErrorDev( + expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev( 'Legacy context API has been detected within a strict-mode tree.\n\n' + 'The old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.\n\n' + - 'Please update the following components: Child, MiddleContextProvider, TopContextProvider', - {withoutStack: true}, + 'Please update the following component: TopContextProvider', ); expect(rendered).toEqual(['count:0']); instance.updateCount(); @@ -2848,14 +2821,11 @@ describe('ReactIncremental', () => { , ); - expect(() => - expect(Scheduler).toFlushWithoutYielding(), - ).toErrorDev( + expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev( 'Legacy context API has been detected within a strict-mode tree.\n\n' + 'The old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.\n\n' + - 'Please update the following components: Child, MiddleContextProvider, TopContextProvider', - {withoutStack: true}, + 'Please update the following component: TopContextProvider', ); expect(rendered).toEqual(['count:0, name:brian']); topInstance.updateCount(); @@ -2956,10 +2926,9 @@ describe('ReactIncremental', () => { ReactNoop.render(); expect(() => { expect(Scheduler).toFlushWithoutYielding(); - }).toErrorDev( - ['Legacy context API has been detected within a strict-mode tree'], - {withoutStack: true}, - ); + }).toErrorDev([ + 'Legacy context API has been detected within a strict-mode tree', + ]); } // First, verify that this code path normally receives Fibers as keys, diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js index 519c2d3f3a850..8fb3c7527fab0 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js @@ -1148,14 +1148,11 @@ describe('ReactIncrementalErrorHandling', () => { , ); - expect(() => - expect(Scheduler).toFlushWithoutYielding(), - ).toErrorDev( + expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev( 'Legacy context API has been detected within a strict-mode tree.\n\n' + 'The old API will be supported in all 16.x releases, but ' + 'applications using it should migrate to the new version.\n\n' + - 'Please update the following components: Connector, Provider', - {withoutStack: true}, + 'Please update the following component: Provider', ); // If the context stack does not unwind, span will get 'abcde' @@ -1649,19 +1646,16 @@ describe('ReactIncrementalErrorHandling', () => { ReactNoop.render(); expect(() => { expect(Scheduler).toFlushAndThrow('Oops!'); - }).toErrorDev( - [ - 'Warning: The component appears to be a function component that returns a class instance. ' + - 'Change Provider to a class that extends React.Component instead. ' + - "If you can't use a class try assigning the prototype on the function as a workaround. " + - '`Provider.prototype = React.Component.prototype`. ' + - "Don't use an arrow function since it cannot be called with `new` by React.", - 'Legacy context API has been detected within a strict-mode tree.\n\n' + - 'The old API will be supported in all 16.x releases, but ' + - 'applications using it should migrate to the new version.\n\n' + - 'Please update the following components: Provider', - ], - {withoutStack: 1}, - ); + }).toErrorDev([ + 'Warning: The component appears to be a function component that returns a class instance. ' + + 'Change Provider to a class that extends React.Component instead. ' + + "If you can't use a class try assigning the prototype on the function as a workaround. " + + '`Provider.prototype = React.Component.prototype`. ' + + "Don't use an arrow function since it cannot be called with `new` by React.", + 'Legacy context API has been detected within a strict-mode tree.\n\n' + + 'The old API will be supported in all 16.x releases, but ' + + 'applications using it should migrate to the new version.\n\n' + + 'Please update the following component: Provider', + ]); }); }); diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalPerf-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncrementalPerf-test.internal.js index a88cd8e3a89fd..08c569c23950f 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalPerf-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalPerf-test.internal.js @@ -371,7 +371,7 @@ describe('ReactDebugFiberPerf', () => { 'Using UNSAFE_componentWillUpdate in strict mode is not recommended', 'Legacy context API has been detected within a strict-mode tree', ], - {withoutStack: true}, + {withoutStack: 3}, ); ReactNoop.render(); addComment('Update'); diff --git a/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js b/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js index 03c5ad4eec660..f6e5b5b4a1486 100644 --- a/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js @@ -1197,8 +1197,7 @@ describe('ReactNewContext', () => { 'Legacy context API has been detected within a strict-mode tree.\n\n' + 'The old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.\n\n' + - 'Please update the following components: LegacyProvider', - {withoutStack: true}, + 'Please update the following component: LegacyProvider', ); expect(ReactNoop.getChildren()).toEqual([span('Child')]); diff --git a/packages/react/src/__tests__/ReactStrictMode-test.js b/packages/react/src/__tests__/ReactStrictMode-test.js index 15b2ce719c767..b6e612da507e1 100644 --- a/packages/react/src/__tests__/ReactStrictMode-test.js +++ b/packages/react/src/__tests__/ReactStrictMode-test.js @@ -874,10 +874,11 @@ describe('context legacy', () => { 'Warning: Legacy context API has been detected within a strict-mode tree.' + '\n\nThe old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.' + - '\n\nPlease update the following components: ' + - 'FunctionalLegacyContextConsumer, LegacyContextConsumer, LegacyContextProvider' + + '\n\nPlease update the following component: ' + + 'LegacyContextProvider' + '\n\nLearn more about this warning here: ' + 'https://fb.me/react-legacy-context' + + '\n in LegacyContextProvider (at **)' + '\n in StrictMode (at **)' + '\n in div (at **)' + '\n in Root (at **)',