Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show first component stack in context warning #17922

Merged
merged 2 commits into from Jan 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 7 additions & 4 deletions packages/react-reconciler/src/ReactStrictModeWarnings.js
Expand Up @@ -324,16 +324,19 @@ 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');
didWarnAboutLegacyContext.add(fiber.type);
});

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.' +
Expand All @@ -343,7 +346,7 @@ if (__DEV__) {
'\n\nLearn more about this warning here: https://fb.me/react-legacy-context' +
'%s',
sortedNames,
strictRootComponentStack,
firstComponentStack,
);
},
);
Expand Down
Expand Up @@ -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(
Expand Down Expand Up @@ -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},
);
});

Expand All @@ -2000,14 +1998,11 @@ describe('ReactIncremental', () => {
}

ReactNoop.render(<Recurse />);
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 {}',
Expand Down Expand Up @@ -2041,20 +2036,17 @@ describe('ReactIncremental', () => {
};

ReactNoop.render(<Recurse />);
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
[
'Warning: The <Recurse /> 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 <Recurse /> 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}',
Expand Down Expand Up @@ -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},
);
});

Expand Down Expand Up @@ -2196,14 +2187,11 @@ describe('ReactIncremental', () => {
</IndirectionFn>
</Intl>,
);
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 {}',
Expand Down Expand Up @@ -2292,14 +2280,11 @@ describe('ReactIncremental', () => {
</IndirectionFn>
</Stateful>,
);
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 {}',
Expand Down Expand Up @@ -2365,14 +2350,11 @@ describe('ReactIncremental', () => {

// Init
ReactNoop.render(<Root />);
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
Expand Down Expand Up @@ -2419,14 +2401,11 @@ describe('ReactIncremental', () => {

// Init
ReactNoop.render(<Root />);
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
Expand Down Expand Up @@ -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([
Expand Down Expand Up @@ -2622,14 +2601,11 @@ describe('ReactIncremental', () => {
</TopContextProvider>,
);

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();
Expand Down Expand Up @@ -2688,14 +2664,11 @@ describe('ReactIncremental', () => {
</TopContextProvider>,
);

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();
Expand Down Expand Up @@ -2763,14 +2736,11 @@ describe('ReactIncremental', () => {
</TopContextProvider>,
);

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();
Expand Down Expand Up @@ -2848,14 +2818,11 @@ describe('ReactIncremental', () => {
</TopContextProvider>,
);

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();
Expand Down Expand Up @@ -2956,10 +2923,9 @@ describe('ReactIncremental', () => {
ReactNoop.render(<Boundary />);
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,
Expand Down
Expand Up @@ -1148,14 +1148,11 @@ describe('ReactIncrementalErrorHandling', () => {
<Connector />
</Provider>,
);
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'
Expand Down Expand Up @@ -1649,19 +1646,16 @@ describe('ReactIncrementalErrorHandling', () => {
ReactNoop.render(<Provider />);
expect(() => {
expect(Scheduler).toFlushAndThrow('Oops!');
}).toErrorDev(
[
'Warning: The <Provider /> 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 <Provider /> 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',
]);
});
});
Expand Up @@ -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(<AllLifecycles />);
addComment('Update');
Expand Down
Expand Up @@ -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')]);

Expand Down
1 change: 1 addition & 0 deletions packages/react/src/__tests__/ReactStrictMode-test.js
Expand Up @@ -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 **)',
Expand Down