Skip to content

Commit c325887

Browse files
trueadmjetoneza
authored andcommitted
Show deprecated context object warnings usage in ReactDOM server (facebook#14033)
* Applies context object warnings to ReactDOM server
1 parent 3bd0a9a commit c325887

File tree

2 files changed

+130
-8
lines changed

2 files changed

+130
-8
lines changed

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

+99
Original file line numberDiff line numberDiff line change
@@ -249,5 +249,104 @@ describe('ReactDOMServerIntegration', () => {
249249
expect(e.querySelector('#language2').textContent).toBe('sanskrit');
250250
expect(e.querySelector('#language3').textContent).toBe('french');
251251
});
252+
253+
itRenders(
254+
'should warn with an error message when using Context as consumer in DEV',
255+
async render => {
256+
const Theme = React.createContext('dark');
257+
const Language = React.createContext('french');
258+
259+
const App = () => (
260+
<div>
261+
<Theme.Provider value="light">
262+
<Language.Provider value="english">
263+
<Theme.Provider value="dark">
264+
<Theme>{theme => <div id="theme1">{theme}</div>}</Theme>
265+
</Theme.Provider>
266+
</Language.Provider>
267+
</Theme.Provider>
268+
</div>
269+
);
270+
// We expect 1 error.
271+
await render(<App />, 1);
272+
},
273+
);
274+
275+
// False positive regression test.
276+
itRenders(
277+
'should not warn when using Consumer from React < 16.6 with newer renderer',
278+
async render => {
279+
const Theme = React.createContext('dark');
280+
const Language = React.createContext('french');
281+
// React 16.5 and earlier didn't have a separate object.
282+
Theme.Consumer = Theme;
283+
284+
const App = () => (
285+
<div>
286+
<Theme.Provider value="light">
287+
<Language.Provider value="english">
288+
<Theme.Provider value="dark">
289+
<Theme>{theme => <div id="theme1">{theme}</div>}</Theme>
290+
</Theme.Provider>
291+
</Language.Provider>
292+
</Theme.Provider>
293+
</div>
294+
);
295+
// We expect 0 errors.
296+
await render(<App />, 0);
297+
},
298+
);
299+
300+
itRenders(
301+
'should warn with an error message when using nested context consumers in DEV',
302+
async render => {
303+
const App = () => {
304+
const Theme = React.createContext('dark');
305+
const Language = React.createContext('french');
306+
307+
return (
308+
<div>
309+
<Theme.Provider value="light">
310+
<Language.Provider value="english">
311+
<Theme.Provider value="dark">
312+
<Theme.Consumer.Consumer>
313+
{theme => <div id="theme1">{theme}</div>}
314+
</Theme.Consumer.Consumer>
315+
</Theme.Provider>
316+
</Language.Provider>
317+
</Theme.Provider>
318+
</div>
319+
);
320+
};
321+
// We expect 1 error.
322+
await render(<App />, 1);
323+
},
324+
);
325+
326+
itRenders(
327+
'should warn with an error message when using Context.Consumer.Provider DEV',
328+
async render => {
329+
const App = () => {
330+
const Theme = React.createContext('dark');
331+
const Language = React.createContext('french');
332+
333+
return (
334+
<div>
335+
<Theme.Provider value="light">
336+
<Language.Provider value="english">
337+
<Theme.Consumer.Provider value="dark">
338+
<Theme.Consumer>
339+
{theme => <div id="theme1">{theme}</div>}
340+
</Theme.Consumer>
341+
</Theme.Consumer.Provider>
342+
</Language.Provider>
343+
</Theme.Provider>
344+
</div>
345+
);
346+
};
347+
// We expect 1 error.
348+
await render(<App />, 1);
349+
},
350+
);
252351
});
253352
});

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

+31-8
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@
88
*/
99

1010
import type {ReactElement} from 'shared/ReactElementType';
11-
import type {
12-
ReactProvider,
13-
ReactConsumer,
14-
ReactContext,
15-
} from 'shared/ReactTypes';
11+
import type {ReactProvider, ReactContext} from 'shared/ReactTypes';
1612

1713
import React from 'react';
1814
import invariant from 'shared/invariant';
@@ -93,6 +89,7 @@ let validatePropertiesInDevelopment = (type, props) => {};
9389
let pushCurrentDebugStack = (stack: Array<Frame>) => {};
9490
let pushElementToDebugStack = (element: ReactElement) => {};
9591
let popCurrentDebugStack = () => {};
92+
let hasWarnedAboutUsingContextAsConsumer = false;
9693

9794
if (__DEV__) {
9895
ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;
@@ -1061,9 +1058,35 @@ class ReactDOMServerRenderer {
10611058
return '';
10621059
}
10631060
case REACT_CONTEXT_TYPE: {
1064-
const consumer: ReactConsumer<any> = (nextChild: any);
1065-
const nextProps: any = consumer.props;
1066-
const nextValue = consumer.type._currentValue;
1061+
let reactContext = (nextChild: any).type;
1062+
// The logic below for Context differs depending on PROD or DEV mode. In
1063+
// DEV mode, we create a separate object for Context.Consumer that acts
1064+
// like a proxy to Context. This proxy object adds unnecessary code in PROD
1065+
// so we use the old behaviour (Context.Consumer references Context) to
1066+
// reduce size and overhead. The separate object references context via
1067+
// a property called "_context", which also gives us the ability to check
1068+
// in DEV mode if this property exists or not and warn if it does not.
1069+
if (__DEV__) {
1070+
if ((reactContext: any)._context === undefined) {
1071+
// This may be because it's a Context (rather than a Consumer).
1072+
// Or it may be because it's older React where they're the same thing.
1073+
// We only want to warn if we're sure it's a new React.
1074+
if (reactContext !== reactContext.Consumer) {
1075+
if (!hasWarnedAboutUsingContextAsConsumer) {
1076+
hasWarnedAboutUsingContextAsConsumer = true;
1077+
warning(
1078+
false,
1079+
'Rendering <Context> directly is not supported and will be removed in ' +
1080+
'a future major release. Did you mean to render <Context.Consumer> instead?',
1081+
);
1082+
}
1083+
}
1084+
} else {
1085+
reactContext = (reactContext: any)._context;
1086+
}
1087+
}
1088+
const nextProps: any = (nextChild: any).props;
1089+
const nextValue = reactContext._currentValue;
10671090

10681091
const nextChildren = toArray(nextProps.children(nextValue));
10691092
const frame: Frame = {

0 commit comments

Comments
 (0)