-
Notifications
You must be signed in to change notification settings - Fork 47.4k
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
add legacy context API warning in strict mode #12849
Conversation
|
||
if ( | ||
typeof instance.getChildContext === 'function' || | ||
(fiber.tag === ClassComponent && fiber.type.contextTypes != null) || |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah
Details of bundled changes.Comparing: 397d611...1fe6316 react-dom
react-art
react-test-renderer
react-reconciler
react
react-native-renderer
Generated by 🚫 dangerJS |
There was a problem hiding this 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
Huh, why did the bundle size go up? |
packages/shared/ReactFeatureFlags.js
Outdated
@@ -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; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a link to https://fb.me/react-strict-mode-warnings
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: ' + |
There was a problem hiding this comment.
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,
);
There was a problem hiding this comment.
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 ?
There was a problem hiding this comment.
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
andwarning
in this file and I thought priority-wise this is the same with deprecated lifecycles. But we can definitely change it towarning
, if it needs more attention from developers. - I agree that this wording is better. Will change a bit later.
There was a problem hiding this comment.
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.
I think the new message is a little confusing. Why is this bad? Why is it a warning?
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? |
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)
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 |
This is definitely a good idea! 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
Yeah, sorry. This was a rhetorical question. I was saying that users might ask themselves this when they read the current message. 😄 |
@bvaughn got what you meant. I'll update the PR in a while. Thanks for the explanation! 👍 |
You need to run |
@gaearon Thanks Dan. I think I need to re-familiarize myself with the contributing doc 👍 |
@cyan33 A helpful one-liner to run before committing: yarn prettier && yarn linc && yarn flow dom (You might change |
There was a problem hiding this 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; | ||
} | ||
|
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 😄
There was a problem hiding this comment.
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; | ||
} |
There was a problem hiding this comment.
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); | ||
} |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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.)
There was a problem hiding this comment.
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 😄
There was a problem hiding this comment.
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__;
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.)
packages/react/src/React.js
Outdated
@@ -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'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Accidental?
packages/react/src/React.js
Outdated
@@ -70,7 +70,7 @@ const React = { | |||
}, | |||
}; | |||
|
|||
if (enableSuspense) { | |||
if (true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert this?
@@ -668,6 +668,11 @@ function mountClassInstance( | |||
workInProgress, | |||
instance, | |||
); | |||
|
|||
ReactStrictModeWarnings.recordLegacyContextWarning( |
There was a problem hiding this comment.
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.
@gaearon Could we add |
This PR adds
warning
on the legacy context APIs when it's under StrictMode. Specifically, just to make sure, theif
statement looks like this:Feel free to leave comments.