diff --git a/packages/react-reconciler/src/ReactStrictModeWarnings.js b/packages/react-reconciler/src/ReactStrictModeWarnings.js
index 29af663d90ec..4ace418c233d 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 e39b055f79c5..c20c2e573294 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 519c2d3f3a85..8fb3c7527fab 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 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..f6e5b5b4a148 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 15b2ce719c76..b6e612da507e 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 **)',