Remove propTypes checks for legacy context (#28324)
Part of https://github.com/facebook/react/pull/28207, this is easy to land in isolation. The approach I'm taking is slightly different — instead of leaving validation on for legacy context, I disable the validation (it's DEV-only) and leave just the parts that drive the runtime logic. I.e. `contexTypes` and `childContextTypes` *values* are now ignored, the keys are used just like before.
dan committed
Feb 14, 2024 at 16:22 UTC
64e755d7374d753c75dc16ba1a4a09ce7b8689dd
3 files changed
+2
-171
packages/react-reconciler/src/ReactFiberContext.js
-10
@@ -14,7 +14,6 @@ import {isFiberMounted} from './ReactFiberTreeReflection';
14
import {disableLegacyContext} from 'shared/ReactFeatureFlags';
15
import {ClassComponent, HostRoot} from './ReactWorkTags';
16
import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
17
-import checkPropTypes from 'shared/checkPropTypes';
17
18
import {createCursor, push, pop} from './ReactFiberStack';
19
@@ -101,11 +100,6 @@ function getMaskedContext(
100
context[key] = unmaskedContext[key];
101
}
102
104
- if (__DEV__) {
105
- const name = getComponentNameFromFiber(workInProgress) || 'Unknown';
106
- checkPropTypes(contextTypes, context, 'context', name);
107
- }
108
-
103
// Cache unmasked context so we can avoid recreating masked context unless necessary.
104
// Context is created before the class component is instantiated so check for instance.
105
if (instance) {
@@ -212,10 +206,6 @@ function processChildContext(
206
);
207
}
208
}
215
- if (__DEV__) {
216
- const name = getComponentNameFromFiber(fiber) || 'Unknown';
217
- checkPropTypes(childContextTypes, childContext, 'child context', name);
218
- }
209
210
return {...parentContext, ...childContext};
211
}
packages/react/src/__tests__/ReactContextValidator-test.js
-154
@@ -18,7 +18,6 @@
18
let PropTypes;
19
let React;
20
let ReactDOMClient;
21
-let ReactDOMServer;
21
let ReactTestUtils;
22
let act;
23
@@ -29,7 +28,6 @@ describe('ReactContextValidator', () => {
28
PropTypes = require('prop-types');
29
React = require('react');
30
ReactDOMClient = require('react-dom/client');
32
- ReactDOMServer = require('react-dom/server');
31
ReactTestUtils = require('react-dom/test-utils');
32
act = require('internal-test-utils').act;
33
});
@@ -159,136 +157,6 @@ describe('ReactContextValidator', () => {
157
expect(componentDidUpdateContext).toEqual({foo: 'def'});
158
});
159
162
- // @gate !disableLegacyContext || !__DEV__
163
- it('should check context types', () => {
164
- class Component extends React.Component {
165
- render() {
166
- return <div />;
167
- }
168
- }
169
- Component.contextTypes = {
170
- foo: PropTypes.string.isRequired,
171
- };
172
-
173
- expect(() => ReactTestUtils.renderIntoDocument(<Component />)).toErrorDev(
174
- 'Warning: Failed context type: ' +
175
- 'The context `foo` is marked as required in `Component`, but its value ' +
176
- 'is `undefined`.\n' +
177
- ' in Component (at **)',
178
- );
179
-
180
- class ComponentInFooStringContext extends React.Component {
181
- getChildContext() {
182
- return {
183
- foo: this.props.fooValue,
184
- };
185
- }
186
-
187
- render() {
188
- return <Component />;
189
- }
190
- }
191
- ComponentInFooStringContext.childContextTypes = {
192
- foo: PropTypes.string,
193
- };
194
-
195
- // No additional errors expected
196
- ReactTestUtils.renderIntoDocument(
197
- <ComponentInFooStringContext fooValue={'bar'} />,
198
- );
199
-
200
- class ComponentInFooNumberContext extends React.Component {
201
- getChildContext() {
202
- return {
203
- foo: this.props.fooValue,
204
- };
205
- }
206
-
207
- render() {
208
- return <Component />;
209
- }
210
- }
211
- ComponentInFooNumberContext.childContextTypes = {
212
- foo: PropTypes.number,
213
- };
214
-
215
- expect(() =>
216
- ReactTestUtils.renderIntoDocument(
217
- <ComponentInFooNumberContext fooValue={123} />,
218
- ),
219
- ).toErrorDev(
220
- 'Warning: Failed context type: ' +
221
- 'Invalid context `foo` of type `number` supplied ' +
222
- 'to `Component`, expected `string`.\n' +
223
- ' in Component (at **)\n' +
224
- ' in ComponentInFooNumberContext (at **)',
225
- );
226
- });
227
-
228
- // @gate !disableLegacyContext || !__DEV__
229
- it('should check child context types', () => {
230
- class Component extends React.Component {
231
- getChildContext() {
232
- return this.props.testContext;
233
- }
234
-
235
- render() {
236
- return <div />;
237
- }
238
- }
239
- Component.childContextTypes = {
240
- foo: PropTypes.string.isRequired,
241
- bar: PropTypes.number,
242
- };
243
-
244
- expect(() =>
245
- ReactTestUtils.renderIntoDocument(<Component testContext={{bar: 123}} />),
246
- ).toErrorDev(
247
- 'Warning: Failed child context type: ' +
248
- 'The child context `foo` is marked as required in `Component`, but its ' +
249
- 'value is `undefined`.\n' +
250
- ' in Component (at **)',
251
- );
252
-
253
- expect(() =>
254
- ReactTestUtils.renderIntoDocument(<Component testContext={{foo: 123}} />),
255
- ).toErrorDev(
256
- 'Warning: Failed child context type: ' +
257
- 'Invalid child context `foo` of type `number` ' +
258
- 'supplied to `Component`, expected `string`.\n' +
259
- ' in Component (at **)',
260
- );
261
-
262
- // No additional errors expected
263
- ReactTestUtils.renderIntoDocument(
264
- <Component testContext={{foo: 'foo', bar: 123}} />,
265
- );
266
-
267
- ReactTestUtils.renderIntoDocument(<Component testContext={{foo: 'foo'}} />);
268
- });
269
-
270
- it('warns of incorrect prop types on context provider', () => {
271
- const TestContext = React.createContext();
272
-
273
- TestContext.Provider.propTypes = {
274
- value: PropTypes.string.isRequired,
275
- };
276
-
277
- ReactTestUtils.renderIntoDocument(<TestContext.Provider value="val" />);
278
-
279
- class Component extends React.Component {
280
- render() {
281
- return <TestContext.Provider value={undefined} />;
282
- }
283
- }
284
-
285
- expect(() => ReactTestUtils.renderIntoDocument(<Component />)).toErrorDev(
286
- 'Warning: Failed prop type: The prop `value` is marked as required in ' +
287
- '`Context.Provider`, but its value is `undefined`.\n' +
288
- ' in Component (at **)',
289
- );
290
- });
291
-
160
// TODO (bvaughn) Remove this test and the associated behavior in the future.
161
// It has only been added in Fiber to match the (unintentional) behavior in Stack.
162
// @gate !disableLegacyContext || !__DEV__
@@ -371,8 +239,6 @@ describe('ReactContextValidator', () => {
239
'Warning: MiddleMissingContext.childContextTypes is specified but there is no ' +
240
'getChildContext() method on the instance. You can either define getChildContext() ' +
241
'on MiddleMissingContext or remove childContextTypes from it.',
374
- 'Warning: Failed context type: The context `bar` is marked as required ' +
375
- 'in `ChildContextConsumer`, but its value is `undefined`.',
242
]);
243
expect(childContext.bar).toBeUndefined();
244
expect(childContext.foo).toBe('FOO');
@@ -699,24 +565,4 @@ describe('ReactContextValidator', () => {
565
'Warning: ComponentB: Function components do not support contextType.',
566
);
567
});
702
-
703
- it('should honor a displayName if set on the context type', () => {
704
- const Context = React.createContext(null);
705
- Context.displayName = 'MyContextType';
706
- function Validator() {
707
- return null;
708
- }
709
- Validator.propTypes = {dontPassToSeeErrorStack: PropTypes.bool.isRequired};
710
-
711
- expect(() => {
712
- ReactDOMServer.renderToStaticMarkup(
713
- <Context.Provider>
714
- <Context.Consumer>{() => <Validator />}</Context.Consumer>
715
- </Context.Provider>,
716
- );
717
- }).toErrorDev(
718
- 'Warning: Failed prop type: The prop `dontPassToSeeErrorStack` is marked as required in `Validator`, but its value is `undefined`.\n' +
719
- ' in Validator (at **)',
720
- );
721
- });
568
});
packages/react/src/__tests__/ReactJSXElementValidator-test.js
+2
-7
@@ -312,7 +312,7 @@ describe('ReactJSXElementValidator', () => {
312
});
313
314
// @gate !disableLegacyContext || !__DEV__
315
- it('should warn on invalid context types', () => {
315
+ it('should not warn on invalid context types', () => {
316
class NullContextTypeComponent extends React.Component {
317
render() {
318
return <span>{this.props.prop}</span>;
@@ -321,12 +321,7 @@ describe('ReactJSXElementValidator', () => {
321
NullContextTypeComponent.contextTypes = {
322
prop: null,
323
};
324
- expect(() =>
325
- ReactTestUtils.renderIntoDocument(<NullContextTypeComponent />),
326
- ).toErrorDev(
327
- 'NullContextTypeComponent: context type `prop` is invalid; it must ' +
328
- 'be a function, usually from the `prop-types` package,',
329
- );
324
+ ReactTestUtils.renderIntoDocument(<NullContextTypeComponent />);
325
});
326
327
it('should warn if getDefaultProps is specified on the class', () => {