-
Notifications
You must be signed in to change notification settings - Fork 47.2k
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
Improve warning for invalid class contextType #15142
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,7 +24,7 @@ import shallowEqual from 'shared/shallowEqual'; | |
import getComponentName from 'shared/getComponentName'; | ||
import invariant from 'shared/invariant'; | ||
import warningWithoutStack from 'shared/warningWithoutStack'; | ||
import {REACT_CONTEXT_TYPE} from 'shared/ReactSymbols'; | ||
import {REACT_CONTEXT_TYPE, REACT_PROVIDER_TYPE} from 'shared/ReactSymbols'; | ||
|
||
import {startPhaseTimer, stopPhaseTimer} from './ReactDebugFiberPerf'; | ||
import {resolveDefaultProps} from './ReactFiberLazyComponent'; | ||
|
@@ -513,27 +513,52 @@ function constructClassInstance( | |
let unmaskedContext = emptyContextObject; | ||
let context = null; | ||
const contextType = ctor.contextType; | ||
if (typeof contextType === 'object' && contextType !== null) { | ||
if (__DEV__) { | ||
const isContextConsumer = | ||
|
||
if (__DEV__) { | ||
if ('contextType' in ctor) { | ||
let isValid = | ||
contextType !== null && | ||
contextType !== undefined && | ||
contextType.$$typeof === REACT_CONTEXT_TYPE && | ||
contextType._context !== undefined; | ||
if ( | ||
(contextType.$$typeof !== REACT_CONTEXT_TYPE || isContextConsumer) && | ||
!didWarnAboutInvalidateContextType.has(ctor) | ||
) { | ||
contextType._context === undefined; // Not a <Context.Consumer> | ||
|
||
if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { | ||
didWarnAboutInvalidateContextType.add(ctor); | ||
|
||
let addendum = ''; | ||
if (contextType === null) { | ||
addendum = ' However, it is set to null.'; | ||
} else if (contextType === undefined) { | ||
addendum = | ||
' However, it is set to undefined. ' + | ||
'This can be caused by a typo or by mixing up named and default imports. ' + | ||
'This can also happen due to a circular dependency, so ' + | ||
'try moving the createContext() call to a separate file.'; | ||
} else if (typeof contextType !== 'object') { | ||
addendum = ' However, it is set to ' + typeof contextType + '.'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can add "a" here to make it a little clearer addendum = ' However, it is set to a ' + typeof contextType + '.'; That way it reports "set to a string" instead of "set to string", which sounds better. Same goes for numbers, symbols, and functions. |
||
} else if (contextType.$$typeof === REACT_PROVIDER_TYPE) { | ||
addendum = ' Did you accidentally pass the Context.Provider instead?'; | ||
} else if (contextType._context !== undefined) { | ||
// <Context.Consumer> | ||
addendum = ' Did you accidentally pass the Context.Consumer instead?'; | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add another branch for arrays? else if (Array.isArray(contextType)) {
addendum = 'However, it is set to an array.'
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems very unlikely to happen There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤷♂️ seems like it could happen if you import the wrong value. I figured that if it happens it would be weird to see.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Arrays are pretty rare as export values so I don't think it's worth handling. |
||
addendum = | ||
' However, it is set to an object with keys {' + | ||
Object.keys(contextType).join(', ') + | ||
'}.'; | ||
} | ||
warningWithoutStack( | ||
false, | ||
'%s defines an invalid contextType. ' + | ||
'contextType should point to the Context object returned by React.createContext(). ' + | ||
'Did you accidentally pass the Context.%s instead?', | ||
'contextType should point to the Context object returned by React.createContext().%s', | ||
getComponentName(ctor) || 'Component', | ||
isContextConsumer ? 'Consumer' : 'Provider', | ||
addendum, | ||
); | ||
} | ||
} | ||
} | ||
|
||
if (typeof contextType === 'object' && contextType !== null) { | ||
context = readContext((contextType: any)); | ||
} else { | ||
unmaskedContext = getUnmaskedContext(workInProgress, ctor, 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.
Sometimes it is nice to be able to conditionally set it:
This provides no way to do that while also ensuring you stay declarative.
Is
null
really a common mistake? I'm guessing not since it's the only one you don't have a descriptive message for.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.
Nope. Agree let’s omit it.