diff --git a/packages/react-reconciler/src/ReactStrictModeWarnings.js b/packages/react-reconciler/src/ReactStrictModeWarnings.js index 29af663d90ec..a61185d8bf5f 100644 --- a/packages/react-reconciler/src/ReactStrictModeWarnings.js +++ b/packages/react-reconciler/src/ReactStrictModeWarnings.js @@ -324,6 +324,11 @@ if (__DEV__) { ReactStrictModeWarnings.flushLegacyContextWarning = () => { ((pendingLegacyContextWarning: any): FiberToFiberComponentsMap).forEach( (fiberArray: FiberArray, strictRoot) => { + if (fiberArray.length === 0) { + return; + } + const firstFiber = fiberArray[0]; + const uniqueNames = new Set(); fiberArray.forEach(fiber => { uniqueNames.add(getComponentName(fiber.type) || 'Component'); @@ -331,9 +336,7 @@ if (__DEV__) { }); const sortedNames = setToSortedString(uniqueNames); - const strictRootComponentStack = getStackByFiberInDevAndProd( - strictRoot, - ); + const firstComponentStack = getStackByFiberInDevAndProd(firstFiber); console.error( 'Legacy context API has been detected within a strict-mode tree.' + @@ -343,7 +346,7 @@ if (__DEV__) { '\n\nLearn more about this warning here: https://fb.me/react-legacy-context' + '%s', sortedNames, - strictRootComponentStack, + firstComponentStack, ); }, ); diff --git a/packages/react-reconciler/src/__tests__/ReactIncremental-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncremental-test.internal.js index e39b055f79c5..a5e1a0ace5d2 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncremental-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactIncremental-test.internal.js @@ -1917,7 +1917,6 @@ describe('ReactIncremental', () => { '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}, ); ReactNoop.render( @@ -1974,7 +1973,6 @@ describe('ReactIncremental', () => { '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}, ); }); @@ -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}, ); expect(ops).toEqual([ 'Recurse {}', @@ -2041,20 +2036,17 @@ describe('ReactIncremental', () => { }; ReactNoop.render(); - expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev( - [ - 'Warning: The component appears to be a function component that returns a class instance. ' + - 'Change Recurse 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. " + - '`Recurse.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: Recurse', - ], - {withoutStack: 1}, - ); + expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev([ + 'Warning: The component appears to be a function component that returns a class instance. ' + + 'Change Recurse 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. " + + '`Recurse.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: Recurse', + ]); expect(ops).toEqual([ 'Recurse {}', 'Recurse {"n":2}', @@ -2120,7 +2112,6 @@ describe('ReactIncremental', () => { '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}, ); }); @@ -2196,14 +2187,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}, ); expect(ops).toEqual([ 'Intl:read {}', @@ -2292,14 +2280,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}, ); expect(ops).toEqual([ 'Intl:read {}', @@ -2365,14 +2350,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}, ); // Trigger an update in the middle of the tree @@ -2419,14 +2401,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}, ); // Trigger an update in the middle of the tree @@ -2479,7 +2458,7 @@ describe('ReactIncremental', () => { 'using it should migrate to the new version.\n\n' + 'Please update the following components: MyComponent', ], - {withoutStack: true}, + {withoutStack: 1}, ); expect(ops).toEqual([ @@ -2622,14 +2601,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}, ); expect(rendered).toEqual(['count:0']); instance.updateCount(); @@ -2688,14 +2664,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}, ); expect(rendered).toEqual(['count:0']); instance.updateCount(); @@ -2763,14 +2736,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}, ); expect(rendered).toEqual(['count:0']); instance.updateCount(); @@ -2848,14 +2818,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}, ); expect(rendered).toEqual(['count:0, name:brian']); topInstance.updateCount(); @@ -2956,10 +2923,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 519c2d3f3a85..bcb74b6ea07f 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}, ); // 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 components: Provider', + ]); }); }); diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalPerf-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncrementalPerf-test.internal.js index a88cd8e3a89f..08c569c23950 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 03c5ad4eec66..34d854f78cdd 100644 --- a/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js @@ -1198,7 +1198,6 @@ describe('ReactNewContext', () => { '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}, ); 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 15b2ce719c76..3acdab4ac3b5 100644 --- a/packages/react/src/__tests__/ReactStrictMode-test.js +++ b/packages/react/src/__tests__/ReactStrictMode-test.js @@ -878,6 +878,7 @@ describe('context legacy', () => { 'FunctionalLegacyContextConsumer, LegacyContextConsumer, 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 **)',