Skip to content

Commit df7b87d

Browse files
awearygaearon
authored andcommitted
Warn for Context.Consumer with contextType (#14831)
1 parent 2b93d68 commit df7b87d

File tree

4 files changed

+55
-7
lines changed

4 files changed

+55
-7
lines changed

packages/react-dom/src/__tests__/ReactServerRendering-test.js

+39
Original file line numberDiff line numberDiff line change
@@ -904,4 +904,43 @@ describe('ReactDOMServer', () => {
904904
' in App (at **)',
905905
]);
906906
});
907+
908+
it('should warn if an invalid contextType is defined', () => {
909+
const Context = React.createContext();
910+
911+
class ComponentA extends React.Component {
912+
// It should warn for both Context.Consumer and Context.Provider
913+
static contextType = Context.Consumer;
914+
render() {
915+
return <div />;
916+
}
917+
}
918+
class ComponentB extends React.Component {
919+
static contextType = Context.Provider;
920+
render() {
921+
return <div />;
922+
}
923+
}
924+
925+
expect(() => {
926+
ReactDOMServer.renderToString(<ComponentA />);
927+
}).toWarnDev(
928+
'Warning: ComponentA defines an invalid contextType. ' +
929+
'contextType should point to the Context object returned by React.createContext(). ' +
930+
'Did you accidentally pass the Context.Consumer instead?',
931+
{withoutStack: true},
932+
);
933+
934+
// Warnings should be deduped by component type
935+
ReactDOMServer.renderToString(<ComponentA />);
936+
937+
expect(() => {
938+
ReactDOMServer.renderToString(<ComponentB />);
939+
}).toWarnDev(
940+
'Warning: ComponentB defines an invalid contextType. ' +
941+
'contextType should point to the Context object returned by React.createContext(). ' +
942+
'Did you accidentally pass the Context.Provider instead?',
943+
{withoutStack: true},
944+
);
945+
});
907946
});

packages/react-dom/src/server/ReactPartialRendererContext.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,20 @@ export function processContext(
7777
const contextType = type.contextType;
7878
if (typeof contextType === 'object' && contextType !== null) {
7979
if (__DEV__) {
80-
if (contextType.$$typeof !== REACT_CONTEXT_TYPE) {
80+
const isContextConsumer =
81+
contextType.$$typeof === REACT_CONTEXT_TYPE &&
82+
contextType._context !== undefined;
83+
if (contextType.$$typeof !== REACT_CONTEXT_TYPE || isContextConsumer) {
8184
let name = getComponentName(type) || 'Component';
8285
if (!didWarnAboutInvalidateContextType[name]) {
8386
didWarnAboutInvalidateContextType[name] = true;
8487
warningWithoutStack(
8588
false,
8689
'%s defines an invalid contextType. ' +
8790
'contextType should point to the Context object returned by React.createContext(). ' +
88-
'Did you accidentally pass the Context.Provider instead?',
91+
'Did you accidentally pass the Context.%s instead?',
8992
name,
93+
isContextConsumer ? 'Consumer' : 'Provider',
9094
);
9195
}
9296
}

packages/react-reconciler/src/ReactFiberClassComponent.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -515,17 +515,21 @@ function constructClassInstance(
515515
const contextType = ctor.contextType;
516516
if (typeof contextType === 'object' && contextType !== null) {
517517
if (__DEV__) {
518+
const isContextConsumer =
519+
contextType.$$typeof === REACT_CONTEXT_TYPE &&
520+
contextType._context !== undefined;
518521
if (
519-
contextType.$$typeof !== REACT_CONTEXT_TYPE &&
522+
(contextType.$$typeof !== REACT_CONTEXT_TYPE || isContextConsumer) &&
520523
!didWarnAboutInvalidateContextType.has(ctor)
521524
) {
522525
didWarnAboutInvalidateContextType.add(ctor);
523526
warningWithoutStack(
524527
false,
525528
'%s defines an invalid contextType. ' +
526529
'contextType should point to the Context object returned by React.createContext(). ' +
527-
'Did you accidentally pass the Context.Provider instead?',
530+
'Did you accidentally pass the Context.%s instead?',
528531
getComponentName(ctor) || 'Component',
532+
isContextConsumer ? 'Consumer' : 'Provider',
529533
);
530534
}
531535
}

packages/react/src/__tests__/ReactContextValidator-test.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -541,9 +541,10 @@ describe('ReactContextValidator', () => {
541541

542542
it('should warn if an invalid contextType is defined', () => {
543543
const Context = React.createContext();
544-
544+
// This tests that both Context.Consumer and Context.Provider
545+
// warn about invalid contextType.
545546
class ComponentA extends React.Component {
546-
static contextType = Context.Provider;
547+
static contextType = Context.Consumer;
547548
render() {
548549
return <div />;
549550
}
@@ -560,7 +561,7 @@ describe('ReactContextValidator', () => {
560561
}).toWarnDev(
561562
'Warning: ComponentA defines an invalid contextType. ' +
562563
'contextType should point to the Context object returned by React.createContext(). ' +
563-
'Did you accidentally pass the Context.Provider instead?',
564+
'Did you accidentally pass the Context.Consumer instead?',
564565
{withoutStack: true},
565566
);
566567

0 commit comments

Comments
 (0)