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

add legacy context API warning in strict mode #12849

Merged
merged 7 commits into from
May 22, 2018
Merged

add legacy context API warning in strict mode #12849

merged 7 commits into from
May 22, 2018

Conversation

cyan33
Copy link
Contributor

@cyan33 cyan33 commented May 17, 2018

This PR adds warning on the legacy context APIs when it's under StrictMode. Specifically, just to make sure, the if statement looks like this:

if (
  typeof instance.getChildContext === 'function' ||
  (fiber.tag === ClassComponent && fiber.type.contextTypes != null) ||
  (fiber.tag === ClassComponent && fiber.type.childContextTypes != null)
)

Feel free to leave comments.

image


if (
typeof instance.getChildContext === 'function' ||
(fiber.tag === ClassComponent && fiber.type.contextTypes != null) ||
Copy link
Collaborator

@acdlite acdlite May 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't have to check the tag since this is already part of a class-only code path.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So should fiber.tag === ClassComponent be removed in this case?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah

@pull-bot
Copy link

pull-bot commented May 17, 2018

Details of bundled changes.

Comparing: 397d611...1fe6316

react-dom

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-dom.development.js +0.3% +0.2% 617.64 KB 619.75 KB 143.99 KB 144.24 KB UMD_DEV
react-dom.development.js +0.3% +0.2% 602.01 KB 604.11 KB 139.99 KB 140.25 KB NODE_DEV
react-dom-server.browser.development.js 0.0% 0.0% 101.51 KB 101.54 KB 26.47 KB 26.48 KB UMD_DEV
react-dom-server.browser.development.js 0.0% +0.1% 90.81 KB 90.84 KB 24.22 KB 24.23 KB NODE_DEV
react-dom-server.node.development.js 0.0% +0.1% 92.73 KB 92.77 KB 24.76 KB 24.77 KB NODE_DEV
ReactDOM-dev.js +0.4% +0.3% 623.77 KB 626.36 KB 142.63 KB 143 KB FB_WWW_DEV
ReactDOMServer-dev.js +0.4% +0.6% 94.27 KB 94.62 KB 23.95 KB 24.1 KB FB_WWW_DEV

react-art

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-art.development.js +0.5% +0.3% 400.77 KB 402.87 KB 89.75 KB 90 KB UMD_DEV
react-art.development.js +0.6% +0.4% 326.62 KB 328.73 KB 70.83 KB 71.09 KB NODE_DEV
ReactART-dev.js +0.8% +0.5% 331.62 KB 334.21 KB 70.12 KB 70.5 KB FB_WWW_DEV

react-test-renderer

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-test-renderer.development.js +0.6% +0.3% 336.61 KB 338.68 KB 72.95 KB 73.19 KB UMD_DEV
react-test-renderer.development.js +0.6% +0.4% 327.45 KB 329.52 KB 70.2 KB 70.45 KB NODE_DEV
ReactTestRenderer-dev.js +0.7% +0.4% 333.1 KB 335.34 KB 69.79 KB 70.05 KB FB_WWW_DEV

react-reconciler

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-reconciler.development.js +0.7% +0.4% 321.1 KB 323.2 KB 68.18 KB 68.45 KB NODE_DEV
react-reconciler-persistent.development.js +0.6% +0.4% 319.69 KB 321.75 KB 67.6 KB 67.84 KB NODE_DEV

react

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react.development.js +0.1% +0.1% 57.11 KB 57.14 KB 15.87 KB 15.88 KB UMD_DEV
react.development.js +0.1% +0.1% 47.75 KB 47.78 KB 13.53 KB 13.54 KB NODE_DEV
React-dev.js +0.7% +1.2% 47.64 KB 48 KB 13.04 KB 13.19 KB FB_WWW_DEV

react-native-renderer

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
ReactNativeRenderer-dev.js +0.5% +0.3% 454.47 KB 456.71 KB 99.59 KB 99.85 KB RN_FB_DEV
ReactNativeRenderer-dev.js +0.5% +0.3% 454.13 KB 456.37 KB 99.52 KB 99.78 KB RN_OSS_DEV
ReactFabric-dev.js +0.5% +0.3% 445.28 KB 447.52 KB 97.29 KB 97.54 KB RN_FB_DEV
ReactFabric-dev.js +0.5% +0.3% 445.32 KB 447.56 KB 97.31 KB 97.56 KB RN_OSS_DEV

Generated by 🚫 dangerJS

Copy link
Collaborator

@acdlite acdlite left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me but please get approval from @bvaughn, too

@acdlite
Copy link
Collaborator

acdlite commented May 17, 2018

Huh, why did the bundle size go up?

@@ -39,6 +39,9 @@ export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
// Warn about deprecated, async-unsafe lifecycles; relates to RFC #6:
export const warnAboutDeprecatedLifecycles = false;

// Warn about legacy context APIs
export const warnAboutLegacyContextAPIs = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new feature flag should be added to the other *FeatureFlag files as well. Flow should warn about this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just have added to other files. Now running yarn flow gives out 0 errors 😄

'which are subjected to be removed in the future. Please switch to the new ones: ' +
'\n\n%s' +
'\n\nLearn more about this warning here:' +
'', // redirection link goes here
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lowPriorityWarning(
false,
'Below are the components that are using legacy context API, ' +
'which are subjected to be removed in the future. Please switch to the new ones: ' +
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of thoughts:

  • We should probably add the strict root component stack (like we do above with the unsafe lifecycle warning).
  • Why low priority warning instead of a warning?
  • I'm not sure this warning message matches the tone of our other warnings. Maybe something like...
warning(
  false,
  'Legacy context usage has been detected within a strict-mode tree:%s' +
    '\n\n%s' +
    '\n\nLearn more about this warning here:' +
    '\nhttps://fb.me/react-strict-mode-warnings',
    strictRootComponentStack,
    sortedNames,
);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are your thoughts about this proposed wording change, @cyan33 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I missed this comment.

  • Consistence wise, I agree. But do we really need to show the component stack? I think the stack information sometimes could easily be noise.
  • I'm not quite sure, because I have seen both lowPriorityWarning and warning in this file and I thought priority-wise this is the same with deprecated lifecycles. But we can definitely change it to warning, if it needs more attention from developers.
  • I agree that this wording is better. Will change a bit later.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the Profiler component stack could be useful. There's a precedent of including that for other warnings. But I wouldn't say it was necessary.

The suggestion of warning vs lowPriorityWarning was more of a consistency with other, pre-existing StrictMode warnings.

@cyan33 cyan33 changed the title add legacy context APIs warning in strict mode add legacy context API warning in strict mode May 17, 2018
@cyan33
Copy link
Contributor Author

cyan33 commented May 18, 2018

I've further refactored the wording and change it to warning according to @bvaughn 's comment. Don't know if should print out the strict component stack though. What's your opinion? @acdlite

@bvaughn
Copy link
Contributor

bvaughn commented May 18, 2018

Legacy context API has been detected within these components

I think the new message is a little confusing. Why is this bad? Why is it a warning?

Legacy context usage has been detected within a strict-mode tree

I think this message is also a little vague, but at least explicitly mentioning strict-mode is a tip about why it's important. Thoughts?

@cyan33
Copy link
Contributor Author

cyan33 commented May 18, 2018

at least explicitly mentioning strict-mode is a tip about why it's important.

My initial thought is to display the name of the components themselves that have the legacy API inside, not the StrictMode wrapper. (But we can do both if necessary) So I didn't add any wording related to strict mode. (On second thought tho, explicitly mentioning strict mode does make sense to me)

Why is it a warning?

To keep the consistency with the warnings of lifecycle methods.

I'm still not one hundred percent sure about what's the best warning practice in React. So I'd be much appreciated to hear more suggestions on it. @bvaughn

@bvaughn
Copy link
Contributor

bvaughn commented May 18, 2018

My initial thought is to display the name of the components themselves that have the legacy API inside, not the StrictMode wrapper.

This is definitely a good idea! StrictMode might wrap a lot of components, so we definitely want to call out specific ones by name.

I think it's also helpful to mention strict mode in the warning message too though, because it will remind users why we are warning about legacy context (when it has not even been deprecated).

I think it's also helpful to show the strict mode component stack, in case a component is used in multiple places (both inside of and outside of a StrictMode). This will tip users off to where the component is within their app that's causing the warning to be displayed.

To keep the consistency with the warnings of lifecycle methods.

Yeah, sorry. This was a rhetorical question. I was saying that users might ask themselves this when they read the current message. 😄

@cyan33
Copy link
Contributor Author

cyan33 commented May 18, 2018

@bvaughn got what you meant. I'll update the PR in a while. Thanks for the explanation! 👍

@cyan33
Copy link
Contributor Author

cyan33 commented May 18, 2018

@bvaughn @acdlite Please have a final quick review and the screenshot has also been updated at the top description of this PR. Much appreciated! 😄

Also, the format checks seem to have failed on the warnings and the error log seems quite elusive to me. Any clues?

@gaearon
Copy link
Collaborator

gaearon commented May 19, 2018

You need to run yarn prettier locally and then commit and push.

@cyan33
Copy link
Contributor Author

cyan33 commented May 19, 2018

@gaearon Thanks Dan. I think I need to re-familiarize myself with the contributing doc 👍

@bvaughn
Copy link
Contributor

bvaughn commented May 21, 2018

@cyan33 A helpful one-liner to run before committing:

yarn prettier && yarn linc && yarn flow dom

(You might change flow dom to something else if you're working on a different renderer.)

Copy link
Contributor

@bvaughn bvaughn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. I left a few suggestions, mostly minor. 👍

if (didWarnAboutUnsafeLifecycles.has(fiber.type)) {
return;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did these lines move above the StrictRoot ancestor check? I don't think they should have.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I move it upwards intentionally. Because I was thinking that maybe we should not spare time to find its strict node if we already warned this fiber? in which case the findStrictNode becomes extraneous operations.

Tell me if I was wrong.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally, I think error sanity checks (like the StrictRoot check) belong first in the function. In this case, I guess I agree that it doesn't matter practically speaking.

Your call 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense to me now. I agree.

// Dedup strategy: Warn once per component.
if (didWarnAboutLegacyContext.has(fiber.type)) {
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Should the StrictMode ancestor check (below) come before this early return?

if (warningsForRoot === undefined) {
warningsForRoot = [];
pendingLegacyContextWarning.set(strictRoot, warningsForRoot);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not initialize the Set until we actually have something to warn about? (In other words, can we move this initialization into the conditional below?) Seems like that would be a little better for perf.

I think this would also let us skip the fiberArray.length > 0 check in the forEach below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point.

fiber.type.childContextTypes != null
) {
warningsForRoot.push(fiber);
pendingLegacyContextWarning.set(strictRoot, warningsForRoot);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: We don't actually need to re-set this in the Map do we?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it because when we do let warningsForRoot = pendingLegacyContextWarning.get(strictRoot);

and warningsForRoot.push is mutating the content in pendingLegacyContextWarning?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it was creating a new copy. I'll delete this line.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. You're updating the reference that's already stored in the Map.

@@ -14,6 +14,7 @@ const ReactFeatureFlags = {
debugRenderPhaseSideEffects: false,
debugRenderPhaseSideEffectsForStrictMode: false,
warnAboutDeprecatedLifecycles: true,
warnAboutLegacyContextAPI: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curiosity question: Did we intentionally turn this on for RN renderer but not but for www? (It's probably good to turn it on for both.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this. Maybe ask @acdlite 😄

Copy link
Contributor

@bvaughn bvaughn May 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's turn it on for the following feature flag forks:

  • ReactFeatureFlags.native-fb.js
  • ReactFeatureFlags.native-fabric-fb.js
  • ReactFeatureFlags.www.js
export const warnAboutLegacyContextAPI = __DEV__;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we realize this causes problems during the next www sync (which I'll be running) we can back it off then.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are they ever off? It's only read in strict mode, yeah? My understanding was that these warnAbout- feature flags only exist so we can turn them off in certain tests.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two side effect flags are controlled by GKs internally. They're off by default, but can be turned on by injection. (xplat feature flags can't directly reference MobileConfig for GKs like www can.)

@@ -14,7 +14,7 @@ import {
REACT_STRICT_MODE_TYPE,
REACT_TIMEOUT_TYPE,
} from 'shared/ReactSymbols';
import {enableSuspense} from 'shared/ReactFeatureFlags';
// import {enableSuspense} from 'shared/ReactFeatureFlags';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accidental?

@@ -70,7 +70,7 @@ const React = {
},
};

if (enableSuspense) {
if (true) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert this?

@cyan33 cyan33 merged commit 7350358 into facebook:master May 22, 2018
@@ -668,6 +668,11 @@ function mountClassInstance(
workInProgress,
instance,
);

ReactStrictModeWarnings.recordLegacyContextWarning(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we're not catching functional components here. They can also have contextTypes and should also be warned about.

@NE-SmallTown
Copy link
Contributor

NE-SmallTown commented Aug 9, 2018

@gaearon Could we add yarn prettier to pre-commit hook to avoid we forget it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants