@samitouri / QOS-React-1 / commits / 64e755d737

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', () => {