Skip to content

Commit 74fa741

Browse files
committed
Warn about legacy context when legacy context is not disabled
For environments that still have legacy contexts available, this adds a warning to make the remaining call sites easier to locate and encourage upgrades.
1 parent 39e69dc commit 74fa741

17 files changed

+259
-76
lines changed

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ let React;
1313
let ReactDOM;
1414
let PropTypes;
1515
let ReactDOMClient;
16-
let root;
1716
let Scheduler;
17+
1818
let act;
19+
let assertConsoleErrorDev;
1920
let assertLog;
21+
let root;
2022

2123
describe('ReactDOMFiber', () => {
2224
let container;
@@ -29,7 +31,7 @@ describe('ReactDOMFiber', () => {
2931
ReactDOMClient = require('react-dom/client');
3032
Scheduler = require('scheduler');
3133
act = require('internal-test-utils').act;
32-
assertLog = require('internal-test-utils').assertLog;
34+
({assertConsoleErrorDev, assertLog} = require('internal-test-utils'));
3335

3436
container = document.createElement('div');
3537
document.body.appendChild(container);
@@ -732,6 +734,10 @@ describe('ReactDOMFiber', () => {
732734
await act(async () => {
733735
root.render(<Parent />);
734736
});
737+
assertConsoleErrorDev([
738+
'Parent uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
739+
'Component uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
740+
]);
735741
expect(container.innerHTML).toBe('');
736742
expect(portalContainer.innerHTML).toBe('<div>bar</div>');
737743
});

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

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ let ReactDOMFizzServer;
2727
let ReactDOMFizzStatic;
2828
let Suspense;
2929
let SuspenseList;
30+
31+
let assertConsoleErrorDev;
3032
let useSyncExternalStore;
3133
let useSyncExternalStoreWithSelector;
3234
let use;
@@ -116,12 +118,14 @@ describe('ReactDOMFizzServer', () => {
116118
useActionState = React.useActionState;
117119
}
118120

119-
const InternalTestUtils = require('internal-test-utils');
120-
waitForAll = InternalTestUtils.waitForAll;
121-
waitFor = InternalTestUtils.waitFor;
122-
waitForPaint = InternalTestUtils.waitForPaint;
123-
assertLog = InternalTestUtils.assertLog;
124-
clientAct = InternalTestUtils.act;
121+
({
122+
assertConsoleErrorDev,
123+
assertLog,
124+
act: clientAct,
125+
waitFor,
126+
waitForAll,
127+
waitForPaint,
128+
} = require('internal-test-utils'));
125129

126130
if (gate(flags => flags.source)) {
127131
// The `with-selector` module composes the main `use-sync-external-store`
@@ -1950,6 +1954,10 @@ describe('ReactDOMFizzServer', () => {
19501954
);
19511955
pipe(writable);
19521956
});
1957+
assertConsoleErrorDev([
1958+
'TestProvider uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
1959+
'TestConsumer uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
1960+
]);
19531961
expect(getVisibleChildren(container)).toEqual(
19541962
<div>
19551963
Loading: <b>A</b>

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ describe('ReactDOMServerIntegration', () => {
8080
<PurpleContext>
8181
<ClassChildWithContext />
8282
</PurpleContext>,
83+
2,
8384
);
8485
expect(e.textContent).toBe('purple');
8586
});
@@ -94,6 +95,7 @@ describe('ReactDOMServerIntegration', () => {
9495
<PurpleContext>
9596
<FunctionChildWithContext />
9697
</PurpleContext>,
98+
2,
9799
);
98100
expect(e.textContent).toBe('purple');
99101
});
@@ -110,6 +112,7 @@ describe('ReactDOMServerIntegration', () => {
110112
<PurpleContext>
111113
<ClassChildWithoutContext />
112114
</PurpleContext>,
115+
1,
113116
);
114117
expect(e.textContent).toBe('');
115118
});
@@ -124,6 +127,7 @@ describe('ReactDOMServerIntegration', () => {
124127
<PurpleContext>
125128
<FunctionChildWithoutContext />
126129
</PurpleContext>,
130+
1,
127131
);
128132
expect(e.textContent).toBe('');
129133
});
@@ -141,6 +145,7 @@ describe('ReactDOMServerIntegration', () => {
141145
<PurpleContext>
142146
<ClassChildWithWrongContext />
143147
</PurpleContext>,
148+
2,
144149
);
145150
expect(e.textContent).toBe('');
146151
});
@@ -158,6 +163,7 @@ describe('ReactDOMServerIntegration', () => {
158163
<PurpleContext>
159164
<FunctionChildWithWrongContext />
160165
</PurpleContext>,
166+
2,
161167
);
162168
expect(e.textContent).toBe('');
163169
});
@@ -174,6 +180,7 @@ describe('ReactDOMServerIntegration', () => {
174180
<PurpleContext>
175181
<Child />
176182
</PurpleContext>,
183+
2,
177184
);
178185
expect(e.textContent).toBe('purple');
179186
});
@@ -190,6 +197,7 @@ describe('ReactDOMServerIntegration', () => {
190197
<Grandchild />
191198
</RedContext>
192199
</PurpleContext>,
200+
2,
193201
);
194202
expect(e.textContent).toBe('red');
195203
});
@@ -228,7 +236,7 @@ describe('ReactDOMServerIntegration', () => {
228236
text2: PropTypes.string,
229237
};
230238

231-
const e = await render(<Parent />);
239+
const e = await render(<Parent />, 3);
232240
expect(e.querySelector('#first').textContent).toBe('purple');
233241
expect(e.querySelector('#second').textContent).toBe('red');
234242
});
@@ -254,7 +262,7 @@ describe('ReactDOMServerIntegration', () => {
254262
};
255263
Child.contextTypes = {text: PropTypes.string};
256264

257-
const e = await render(<WillMountContext />);
265+
const e = await render(<WillMountContext />, 2);
258266
expect(e.textContent).toBe('foo');
259267
},
260268
);
@@ -278,7 +286,8 @@ describe('ReactDOMServerIntegration', () => {
278286
}
279287
const e = await render(
280288
<ForgetfulParent />,
281-
render === clientRenderOnBadMarkup ? 2 : 1,
289+
// Some warning is not de-duped and logged again on the client retry render.
290+
render === clientRenderOnBadMarkup ? 3 : 2,
282291
);
283292
expect(e.textContent).toBe('nope');
284293
},

packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ describe('ReactErrorBoundaries', () => {
3636
let RetryErrorBoundary;
3737
let Normal;
3838
let assertLog;
39+
let assertConsoleErrorDev;
3940

4041
beforeEach(() => {
4142
jest.useFakeTimers();
@@ -47,8 +48,7 @@ describe('ReactErrorBoundaries', () => {
4748
act = require('internal-test-utils').act;
4849
Scheduler = require('scheduler');
4950

50-
const InternalTestUtils = require('internal-test-utils');
51-
assertLog = InternalTestUtils.assertLog;
51+
({assertLog, assertConsoleErrorDev} = require('internal-test-utils'));
5252

5353
BrokenConstructor = class extends React.Component {
5454
constructor(props) {
@@ -895,6 +895,9 @@ describe('ReactErrorBoundaries', () => {
895895
</ErrorBoundary>,
896896
);
897897
});
898+
assertConsoleErrorDev([
899+
'BrokenComponentWillMountWithContext uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
900+
]);
898901
expect(container.firstChild.textContent).toBe('Caught an error: Hello.');
899902
});
900903

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ let PropTypes;
1313
let React;
1414
let ReactDOMClient;
1515
let act;
16+
let assertConsoleErrorDev;
1617

1718
function FunctionComponent(props) {
1819
return <div>{props.name}</div>;
@@ -24,7 +25,7 @@ describe('ReactFunctionComponent', () => {
2425
PropTypes = require('prop-types');
2526
React = require('react');
2627
ReactDOMClient = require('react-dom/client');
27-
act = require('internal-test-utils').act;
28+
({act, assertConsoleErrorDev} = require('internal-test-utils'));
2829
});
2930

3031
it('should render stateless component', async () => {
@@ -109,6 +110,10 @@ describe('ReactFunctionComponent', () => {
109110
root.render(<GrandParent test="test" />);
110111
});
111112

113+
assertConsoleErrorDev([
114+
'Child uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
115+
]);
116+
112117
expect(el.textContent).toBe('test');
113118

114119
await act(() => {
@@ -472,6 +477,9 @@ describe('ReactFunctionComponent', () => {
472477
await act(() => {
473478
root.render(<Parent />);
474479
});
480+
assertConsoleErrorDev([
481+
'Child uses the legacy contextTypes API which will be removed soon. Use React.createContext() with React.useContext() instead.',
482+
]);
475483
expect(el.textContent).toBe('en');
476484
});
477485

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ let ReactDOM;
1414
let findDOMNode;
1515
let ReactDOMClient;
1616
let PropTypes;
17+
1718
let act;
19+
let assertConsoleErrorDev;
1820

1921
describe('ReactLegacyCompositeComponent', () => {
2022
beforeEach(() => {
@@ -26,7 +28,7 @@ describe('ReactLegacyCompositeComponent', () => {
2628
ReactDOM.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE
2729
.findDOMNode;
2830
PropTypes = require('prop-types');
29-
act = require('internal-test-utils').act;
31+
({act, assertConsoleErrorDev} = require('internal-test-utils'));
3032
});
3133

3234
// @gate !disableLegacyMode
@@ -119,6 +121,10 @@ describe('ReactLegacyCompositeComponent', () => {
119121
await act(() => {
120122
root.render(<Parent ref={current => (component = current)} />);
121123
});
124+
assertConsoleErrorDev([
125+
'Child uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
126+
'Grandchild uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
127+
]);
122128
expect(findDOMNode(component).innerHTML).toBe('bar');
123129
});
124130

@@ -183,6 +189,11 @@ describe('ReactLegacyCompositeComponent', () => {
183189
expect(parentInstance.state.flag).toBe(false);
184190
expect(childInstance.context).toEqual({foo: 'bar', flag: false});
185191

192+
assertConsoleErrorDev([
193+
'Parent uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
194+
'Child uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
195+
]);
196+
186197
await act(() => {
187198
parentInstance.setState({flag: true});
188199
});
@@ -242,6 +253,11 @@ describe('ReactLegacyCompositeComponent', () => {
242253
root.render(<Wrapper ref={current => (wrapper = current)} />);
243254
});
244255

256+
assertConsoleErrorDev([
257+
'Parent uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
258+
'Child uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
259+
]);
260+
245261
expect(wrapper.parentRef.current.state.flag).toEqual(true);
246262
expect(wrapper.childRef.current.context).toEqual({flag: true});
247263

@@ -317,6 +333,13 @@ describe('ReactLegacyCompositeComponent', () => {
317333
root.render(<Parent />);
318334
});
319335

336+
assertConsoleErrorDev([
337+
'Parent uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
338+
'Child uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
339+
'Child uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
340+
'Grandchild uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
341+
]);
342+
320343
expect(childInstance.context).toEqual({foo: 'bar', depth: 0});
321344
expect(grandchildInstance.context).toEqual({foo: 'bar', depth: 1});
322345
});
@@ -369,13 +392,20 @@ describe('ReactLegacyCompositeComponent', () => {
369392
await act(() => {
370393
root.render(<Parent ref={current => (parentInstance = current)} />);
371394
});
395+
assertConsoleErrorDev([
396+
'Parent uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
397+
]);
372398

373399
expect(childInstance).toBeNull();
374400

375401
expect(parentInstance.state.flag).toBe(false);
376402
await act(() => {
377403
parentInstance.setState({flag: true});
378404
});
405+
assertConsoleErrorDev([
406+
'Child uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
407+
]);
408+
379409
expect(parentInstance.state.flag).toBe(true);
380410

381411
expect(childInstance.context).toEqual({foo: 'bar', depth: 0});

packages/react-dom/src/__tests__/ReactLegacyErrorBoundaries-test.internal.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,9 @@ describe('ReactLegacyErrorBoundaries', () => {
849849
</ErrorBoundary>,
850850
container,
851851
);
852+
assertConsoleErrorDev([
853+
'BrokenComponentWillMountWithContext uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
854+
]);
852855
expect(container.firstChild.textContent).toBe('Caught an error: Hello.');
853856
});
854857

packages/react-native-renderer/src/__tests__/ReactNativeEvents-test.internal.js

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -227,27 +227,31 @@ test('handles events on text nodes', () => {
227227
}
228228

229229
const log = [];
230-
ReactNative.render(
231-
<ContextHack>
232-
<Text>
233-
<Text
234-
onTouchEnd={() => log.push('string touchend')}
235-
onTouchEndCapture={() => log.push('string touchend capture')}
236-
onTouchStart={() => log.push('string touchstart')}
237-
onTouchStartCapture={() => log.push('string touchstart capture')}>
238-
Text Content
239-
</Text>
240-
<Text
241-
onTouchEnd={() => log.push('number touchend')}
242-
onTouchEndCapture={() => log.push('number touchend capture')}
243-
onTouchStart={() => log.push('number touchstart')}
244-
onTouchStartCapture={() => log.push('number touchstart capture')}>
245-
{123}
230+
expect(() => {
231+
ReactNative.render(
232+
<ContextHack>
233+
<Text>
234+
<Text
235+
onTouchEnd={() => log.push('string touchend')}
236+
onTouchEndCapture={() => log.push('string touchend capture')}
237+
onTouchStart={() => log.push('string touchstart')}
238+
onTouchStartCapture={() => log.push('string touchstart capture')}>
239+
Text Content
240+
</Text>
241+
<Text
242+
onTouchEnd={() => log.push('number touchend')}
243+
onTouchEndCapture={() => log.push('number touchend capture')}
244+
onTouchStart={() => log.push('number touchstart')}
245+
onTouchStartCapture={() => log.push('number touchstart capture')}>
246+
{123}
247+
</Text>
246248
</Text>
247-
</Text>
248-
</ContextHack>,
249-
1,
250-
);
249+
</ContextHack>,
250+
1,
251+
);
252+
}).toErrorDev([
253+
'ContextHack uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
254+
]);
251255

252256
expect(UIManager.createView).toHaveBeenCalledTimes(5);
253257

0 commit comments

Comments
 (0)