diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index ab05fc4eb7f05..8a7ed49f322d7 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -40,7 +40,6 @@ import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent'; import type {TransitionStatus} from './ReactFiberConfig'; import type {Hook} from './ReactFiberHooks'; -import checkPropTypes from 'shared/checkPropTypes'; import { markComponentRenderStarted, markComponentRenderStopped, @@ -401,23 +400,6 @@ function updateForwardRef( // TODO: current can be non-null here even if the component // hasn't yet mounted. This happens after the first render suspends. // We'll need to figure out if this is fine or can cause issues. - - if (__DEV__) { - if (workInProgress.type !== workInProgress.elementType) { - // Lazy component props can't be validated in createElement - // because they're only guaranteed to be resolved here. - const innerPropTypes = Component.propTypes; - if (innerPropTypes) { - checkPropTypes( - innerPropTypes, - nextProps, // Resolved props - 'prop', - getComponentNameFromType(Component), - ); - } - } - } - const render = Component.render; const ref = workInProgress.ref; @@ -507,17 +489,6 @@ function updateMemoComponent( ); } if (__DEV__) { - const innerPropTypes = type.propTypes; - if (innerPropTypes) { - // Inner memo component props aren't currently validated in createElement. - // We could move it there, but we'd still need this for lazy code path. - checkPropTypes( - innerPropTypes, - nextProps, // Resolved props - 'prop', - getComponentNameFromType(type), - ); - } if (Component.defaultProps !== undefined) { const componentName = getComponentNameFromType(type) || 'Unknown'; if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) { @@ -543,20 +514,6 @@ function updateMemoComponent( workInProgress.child = child; return child; } - if (__DEV__) { - const type = Component.type; - const innerPropTypes = type.propTypes; - if (innerPropTypes) { - // Inner memo component props aren't currently validated in createElement. - // We could move it there, but we'd still need this for lazy code path. - checkPropTypes( - innerPropTypes, - nextProps, // Resolved props - 'prop', - getComponentNameFromType(type), - ); - } - } const currentChild = ((current.child: any): Fiber); // This is always exactly one child const hasScheduledUpdateOrContext = checkScheduledUpdateOrContext( current, @@ -592,37 +549,6 @@ function updateSimpleMemoComponent( // TODO: current can be non-null here even if the component // hasn't yet mounted. This happens when the inner render suspends. // We'll need to figure out if this is fine or can cause issues. - - if (__DEV__) { - if (workInProgress.type !== workInProgress.elementType) { - // Lazy component props can't be validated in createElement - // because they're only guaranteed to be resolved here. - let outerMemoType = workInProgress.elementType; - if (outerMemoType.$$typeof === REACT_LAZY_TYPE) { - // We warn when you define propTypes on lazy() - // so let's just skip over it to find memo() outer wrapper. - // Inner props for memo are validated later. - const lazyComponent: LazyComponentType = outerMemoType; - const payload = lazyComponent._payload; - const init = lazyComponent._init; - try { - outerMemoType = init(payload); - } catch (x) { - outerMemoType = null; - } - // Inner propTypes will be validated in the function component path. - const outerPropTypes = outerMemoType && (outerMemoType: any).propTypes; - if (outerPropTypes) { - checkPropTypes( - outerPropTypes, - nextProps, // Resolved (SimpleMemoComponent has no defaultProps) - 'prop', - getComponentNameFromType(outerMemoType), - ); - } - } - } - } if (current !== null) { const prevProps = current.memoizedProps; if ( @@ -1099,22 +1025,6 @@ function updateFunctionComponent( nextProps: any, renderLanes: Lanes, ) { - if (__DEV__) { - if (workInProgress.type !== workInProgress.elementType) { - // Lazy component props can't be validated in createElement - // because they're only guaranteed to be resolved here. - const innerPropTypes = Component.propTypes; - if (innerPropTypes) { - checkPropTypes( - innerPropTypes, - nextProps, // Resolved props - 'prop', - getComponentNameFromType(Component), - ); - } - } - } - let context; if (!disableLegacyContext) { const unmaskedContext = getUnmaskedContext(workInProgress, Component, true); @@ -1253,20 +1163,6 @@ function updateClassComponent( break; } } - - if (workInProgress.type !== workInProgress.elementType) { - // Lazy component props can't be validated in createElement - // because they're only guaranteed to be resolved here. - const innerPropTypes = Component.propTypes; - if (innerPropTypes) { - checkPropTypes( - innerPropTypes, - nextProps, // Resolved props - 'prop', - getComponentNameFromType(Component), - ); - } - } } // Push context providers early to prevent context stack mismatches. @@ -1815,19 +1711,6 @@ function mountLazyComponent( return child; } case MemoComponent: { - if (__DEV__) { - if (workInProgress.type !== workInProgress.elementType) { - const outerPropTypes = Component.propTypes; - if (outerPropTypes) { - checkPropTypes( - outerPropTypes, - resolvedProps, // Resolved for outer only - 'prop', - getComponentNameFromType(Component), - ); - } - } - } child = updateMemoComponent( null, workInProgress, @@ -3549,11 +3432,6 @@ function updateContextProvider( ); } } - const providerPropTypes = workInProgress.type.propTypes; - - if (providerPropTypes) { - checkPropTypes(providerPropTypes, newProps, 'prop', 'Context.Provider'); - } } pushProvider(workInProgress, context, newValue); @@ -4229,19 +4107,6 @@ function beginWork( const unresolvedProps = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props. let resolvedProps = resolveDefaultProps(type, unresolvedProps); - if (__DEV__) { - if (workInProgress.type !== workInProgress.elementType) { - const outerPropTypes = type.propTypes; - if (outerPropTypes) { - checkPropTypes( - outerPropTypes, - resolvedProps, // Resolved for outer only - 'prop', - getComponentNameFromType(type), - ); - } - } - } resolvedProps = resolveDefaultProps(type.type, resolvedProps); return updateMemoComponent( current, diff --git a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js index 36e956256dc60..bc441b8d18213 100644 --- a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js @@ -1,4 +1,3 @@ -let PropTypes; let React; let ReactTestRenderer; let Scheduler; @@ -28,7 +27,6 @@ describe('ReactLazy', () => { ReactFeatureFlags = require('shared/ReactFeatureFlags'); ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false; - PropTypes = require('prop-types'); React = require('react'); Suspense = React.Suspense; lazy = React.lazy; @@ -783,33 +781,12 @@ describe('ReactLazy', () => { ); }); - it('warns about defining propTypes on the outer wrapper', () => { - const LazyText = lazy(() => fakeImport(Text)); - expect(() => { - LazyText.propTypes = {hello: () => {}}; - }).toErrorDev( - 'React.lazy(...): It is not supported to assign `propTypes` to ' + - 'a lazy component import. Either specify them where the component ' + - 'is defined, or create a wrapping component around it.', - {withoutStack: true}, - ); - }); - - async function verifyInnerPropTypesAreChecked( + async function verifyResolvesProps( Add, shouldWarnAboutFunctionDefaultProps, shouldWarnAboutMemoDefaultProps, ) { const LazyAdd = lazy(() => fakeImport(Add)); - expect(() => { - LazyAdd.propTypes = {}; - }).toErrorDev( - 'React.lazy(...): It is not supported to assign `propTypes` to ' + - 'a lazy component import. Either specify them where the component ' + - 'is defined, or create a wrapping component around it.', - {withoutStack: true}, - ); - const root = ReactTestRenderer.create( }> @@ -820,7 +797,6 @@ describe('ReactLazy', () => { ); await waitForAll(['Loading...']); - expect(root).not.toMatchRenderedOutput('22'); // Mount @@ -830,171 +806,126 @@ describe('ReactLazy', () => { shouldWarnAboutFunctionDefaultProps ? [ 'Add: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.', - 'Invalid prop `inner` of type `string` supplied to `Add`, expected `number`.', ] : shouldWarnAboutMemoDefaultProps ? [ 'Add: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.', - 'Invalid prop `inner` of type `string` supplied to `Add`, expected `number`.', ] - : [ - 'Invalid prop `inner` of type `string` supplied to `Add`, expected `number`.', - ], + : [], ); expect(root).toMatchRenderedOutput('22'); // Update - await expect(async () => { - root.update( - }> - - , - ); - await waitForAll([]); - }).toErrorDev( - 'Invalid prop `inner` of type `boolean` supplied to `Add`, expected `number`.', + root.update( + }> + + , ); + await waitForAll([]); expect(root).toMatchRenderedOutput('0'); } - // Note: all "with defaultProps" tests below also verify defaultProps works as expected. - // If we ever delete or move propTypes-related tests, make sure not to delete these. - it('respects propTypes on function component with defaultProps', async () => { + it('resolves props for function component with defaultProps', async () => { function Add(props) { expect(props.innerWithDefault).toBe(42); return props.inner + props.outer; } - Add.propTypes = { - inner: PropTypes.number.isRequired, - innerWithDefault: PropTypes.number.isRequired, - }; Add.defaultProps = { innerWithDefault: 42, }; - await verifyInnerPropTypesAreChecked(Add, true); + await verifyResolvesProps(Add, true); }); - it('respects propTypes on function component without defaultProps', async () => { + it('resolves props for function component without defaultProps', async () => { function Add(props) { return props.inner + props.outer; } - Add.propTypes = { - inner: PropTypes.number.isRequired, - }; - await verifyInnerPropTypesAreChecked(Add); + await verifyResolvesProps(Add); }); - it('respects propTypes on class component with defaultProps', async () => { + it('resolves props for class component with defaultProps', async () => { class Add extends React.Component { render() { expect(this.props.innerWithDefault).toBe(42); return this.props.inner + this.props.outer; } } - Add.propTypes = { - inner: PropTypes.number.isRequired, - innerWithDefault: PropTypes.number.isRequired, - }; Add.defaultProps = { innerWithDefault: 42, }; - await verifyInnerPropTypesAreChecked(Add); + await verifyResolvesProps(Add); }); - it('respects propTypes on class component without defaultProps', async () => { + it('resolves props for class component without defaultProps', async () => { class Add extends React.Component { render() { return this.props.inner + this.props.outer; } } - Add.propTypes = { - inner: PropTypes.number.isRequired, - }; - await verifyInnerPropTypesAreChecked(Add); + await verifyResolvesProps(Add); }); - it('respects propTypes on forwardRef component with defaultProps', async () => { + it('resolves props for forwardRef component with defaultProps', async () => { const Add = React.forwardRef((props, ref) => { expect(props.innerWithDefault).toBe(42); return props.inner + props.outer; }); Add.displayName = 'Add'; - Add.propTypes = { - inner: PropTypes.number.isRequired, - innerWithDefault: PropTypes.number.isRequired, - }; Add.defaultProps = { innerWithDefault: 42, }; - await verifyInnerPropTypesAreChecked(Add); + await verifyResolvesProps(Add); }); - it('respects propTypes on forwardRef component without defaultProps', async () => { + it('resolves props for forwardRef component without defaultProps', async () => { const Add = React.forwardRef((props, ref) => { return props.inner + props.outer; }); Add.displayName = 'Add'; - Add.propTypes = { - inner: PropTypes.number.isRequired, - }; - await verifyInnerPropTypesAreChecked(Add); + await verifyResolvesProps(Add); }); - it('respects propTypes on outer memo component with defaultProps', async () => { + it('resolves props for outer memo component with defaultProps', async () => { let Add = props => { expect(props.innerWithDefault).toBe(42); return props.inner + props.outer; }; Add = React.memo(Add); - Add.propTypes = { - inner: PropTypes.number.isRequired, - innerWithDefault: PropTypes.number.isRequired, - }; Add.defaultProps = { innerWithDefault: 42, }; - await verifyInnerPropTypesAreChecked(Add, false, true); + await verifyResolvesProps(Add, false, true); }); - it('respects propTypes on outer memo component without defaultProps', async () => { + it('resolves props for outer memo component without defaultProps', async () => { let Add = props => { return props.inner + props.outer; }; Add = React.memo(Add); - Add.propTypes = { - inner: PropTypes.number.isRequired, - }; - await verifyInnerPropTypesAreChecked(Add); + await verifyResolvesProps(Add); }); - it('respects propTypes on inner memo component with defaultProps', async () => { + it('resolves props for inner memo component with defaultProps', async () => { const Add = props => { expect(props.innerWithDefault).toBe(42); return props.inner + props.outer; }; Add.displayName = 'Add'; - Add.propTypes = { - inner: PropTypes.number.isRequired, - innerWithDefault: PropTypes.number.isRequired, - }; Add.defaultProps = { innerWithDefault: 42, }; - await verifyInnerPropTypesAreChecked(React.memo(Add), true); + await verifyResolvesProps(React.memo(Add), true); }); - it('respects propTypes on inner memo component without defaultProps', async () => { + it('resolves props for inner memo component without defaultProps', async () => { const Add = props => { return props.inner + props.outer; }; Add.displayName = 'Add'; - Add.propTypes = { - inner: PropTypes.number.isRequired, - }; - await verifyInnerPropTypesAreChecked(React.memo(Add)); + await verifyResolvesProps(React.memo(Add)); }); - it('uses outer resolved props for validating propTypes on memo', async () => { + it('uses outer resolved props on memo', async () => { let T = props => { return ; }; @@ -1002,10 +933,6 @@ describe('ReactLazy', () => { text: 'Inner default text', }; T = React.memo(T); - T.propTypes = { - // Should not be satisfied by the *inner* defaultProps. - text: PropTypes.string.isRequired, - }; const LazyText = lazy(() => fakeImport(T)); const root = ReactTestRenderer.create( }> @@ -1025,21 +952,16 @@ describe('ReactLazy', () => { assertLog(['Inner default text']); }).toErrorDev([ 'T: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.', - 'The prop `text` is marked as required in `T`, but its value is `undefined`', ]); expect(root).toMatchRenderedOutput('Inner default text'); // Update - await expect(async () => { - root.update( - }> - - , - ); - await waitForAll([null]); - }).toErrorDev( - 'The prop `text` is marked as required in `T`, but its value is `null`', + root.update( + }> + + , ); + await waitForAll([null]); expect(root).toMatchRenderedOutput(null); }); diff --git a/packages/react-reconciler/src/__tests__/ReactMemo-test.js b/packages/react-reconciler/src/__tests__/ReactMemo-test.js index 8b59d8d104aaf..972c87d3614c8 100644 --- a/packages/react-reconciler/src/__tests__/ReactMemo-test.js +++ b/packages/react-reconciler/src/__tests__/ReactMemo-test.js @@ -12,7 +12,6 @@ 'use strict'; -let PropTypes; let React; let ReactNoop; let Suspense; @@ -25,7 +24,6 @@ describe('memo', () => { beforeEach(() => { jest.resetModules(); - PropTypes = require('prop-types'); React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); @@ -483,108 +481,39 @@ describe('memo', () => { ); }); - it('validates propTypes declared on the inner component', async () => { - function FnInner(props) { - return props.inner; - } - FnInner.propTypes = {inner: PropTypes.number.isRequired}; - const Fn = React.memo(FnInner); - - // Mount - await expect(async () => { - ReactNoop.render(); - await waitForAll([]); - }).toErrorDev( - 'Invalid prop `inner` of type `string` supplied to `FnInner`, expected `number`.', - ); - - // Update - await expect(async () => { - ReactNoop.render(); - await waitForAll([]); - }).toErrorDev( - 'Invalid prop `inner` of type `boolean` supplied to `FnInner`, expected `number`.', - ); - }); - - it('validates propTypes declared on the outer component', async () => { - function FnInner(props) { - return props.outer; - } - const Fn = React.memo(FnInner); - Fn.propTypes = {outer: PropTypes.number.isRequired}; - - // Mount - await expect(async () => { - ReactNoop.render(); - await waitForAll([]); - }).toErrorDev( - // Outer props are checked in createElement - 'Invalid prop `outer` of type `string` supplied to `FnInner`, expected `number`.', - ); - - // Update - await expect(async () => { - ReactNoop.render(); - await waitForAll([]); - }).toErrorDev( - // Outer props are checked in createElement - 'Invalid prop `outer` of type `boolean` supplied to `FnInner`, expected `number`.', - ); - }); - - it('validates nested propTypes declarations', async () => { + it('handles nested defaultProps declarations', async () => { function Inner(props) { return props.inner + props.middle + props.outer; } - Inner.propTypes = {inner: PropTypes.number.isRequired}; - Inner.defaultProps = {inner: 0}; + Inner.defaultProps = {inner: 1}; const Middle = React.memo(Inner); - Middle.propTypes = {middle: PropTypes.number.isRequired}; - Middle.defaultProps = {middle: 0}; + Middle.defaultProps = {middle: 10}; const Outer = React.memo(Middle); - Outer.propTypes = {outer: PropTypes.number.isRequired}; - Outer.defaultProps = {outer: 0}; + Outer.defaultProps = {outer: 100}; - // No warning expected because defaultProps satisfy both. - ReactNoop.render( -
- -
, - ); + const root = ReactNoop.createRoot(); await expect(async () => { - await waitForAll([]); + await act(() => { + root.render( +
+ +
, + ); + }); }).toErrorDev([ - 'Inner: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.', + 'Support for defaultProps will be removed from memo component', ]); + expect(root).toMatchRenderedOutput(
111
); - // Mount - await expect(async () => { - ReactNoop.render( + await act(async () => { + root.render(
, ); await waitForAll([]); - }).toErrorDev([ - 'Invalid prop `outer` of type `string` supplied to `Inner`, expected `number`.', - 'Invalid prop `middle` of type `string` supplied to `Inner`, expected `number`.', - 'Invalid prop `inner` of type `string` supplied to `Inner`, expected `number`.', - ]); - - // Update - await expect(async () => { - ReactNoop.render( -
- -
, - ); - await waitForAll([]); - }).toErrorDev([ - 'Invalid prop `outer` of type `boolean` supplied to `Inner`, expected `number`.', - 'Invalid prop `middle` of type `boolean` supplied to `Inner`, expected `number`.', - 'Invalid prop `inner` of type `boolean` supplied to `Inner`, expected `number`.', - ]); + }); + expect(root).toMatchRenderedOutput(
234
); }); it('does not drop lower priority state updates when bailing out at higher pri (simple)', async () => { diff --git a/packages/react-server/src/ReactFizzContext.js b/packages/react-server/src/ReactFizzContext.js index 4dcbdf39fee33..b17827cef68a3 100644 --- a/packages/react-server/src/ReactFizzContext.js +++ b/packages/react-server/src/ReactFizzContext.js @@ -9,7 +9,6 @@ import {disableLegacyContext} from 'shared/ReactFeatureFlags'; import getComponentNameFromType from 'shared/getComponentNameFromType'; -import checkPropTypes from 'shared/checkPropTypes'; let warnedAboutMissingGetChildContext; @@ -36,11 +35,6 @@ export function getMaskedContext(type: any, unmaskedContext: Object): Object { context[key] = unmaskedContext[key]; } - if (__DEV__) { - const name = getComponentNameFromType(type) || 'Unknown'; - checkPropTypes(contextTypes, context, 'context', name); - } - return context; } } @@ -84,11 +78,6 @@ export function processChildContext( ); } } - if (__DEV__) { - const name = getComponentNameFromType(type) || 'Unknown'; - checkPropTypes(childContextTypes, childContext, 'child context', name); - } - return {...parentContext, ...childContext}; } } diff --git a/packages/react/src/ReactForwardRef.js b/packages/react/src/ReactForwardRef.js index 4581fa9ca10a2..3d86241430e30 100644 --- a/packages/react/src/ReactForwardRef.js +++ b/packages/react/src/ReactForwardRef.js @@ -36,9 +36,9 @@ export function forwardRef( } if (render != null) { - if (render.defaultProps != null || render.propTypes != null) { + if (render.defaultProps != null) { console.error( - 'forwardRef render functions do not support propTypes or defaultProps. ' + + 'forwardRef render functions do not support defaultProps. ' + 'Did you accidentally pass a React component?', ); } diff --git a/packages/react/src/__tests__/forwardRef-test.js b/packages/react/src/__tests__/forwardRef-test.js index 8a02585a97133..37a35c4e84dbc 100644 --- a/packages/react/src/__tests__/forwardRef-test.js +++ b/packages/react/src/__tests__/forwardRef-test.js @@ -10,14 +10,12 @@ 'use strict'; describe('forwardRef', () => { - let PropTypes; let React; let ReactNoop; let waitForAll; beforeEach(() => { jest.resetModules(); - PropTypes = require('prop-types'); React = require('react'); ReactNoop = require('react-noop-renderer'); @@ -76,7 +74,7 @@ describe('forwardRef', () => { expect(ref.current).toBe(null); }); - it('should support propTypes and defaultProps', async () => { + it('should support defaultProps', async () => { function FunctionComponent({forwardedRef, optional, required}) { return (
@@ -91,10 +89,6 @@ describe('forwardRef', () => { return ; }, ); - RefForwardingComponent.propTypes = { - optional: PropTypes.string, - required: PropTypes.string.isRequired, - }; RefForwardingComponent.defaultProps = { optional: 'default', }; @@ -116,14 +110,6 @@ describe('forwardRef', () => { {text: 'default', hidden: false}, {text: 'foo', hidden: false}, ]); - - expect(() => - ReactNoop.render(), - ).toErrorDev( - 'Warning: Failed prop type: The prop `required` is marked as required in ' + - '`ForwardRef(NamedFunction)`, but its value is `undefined`.\n' + - ' in NamedFunction (at **)', - ); }); it('should warn if not provided a callback during creation', () => { @@ -150,24 +136,14 @@ describe('forwardRef', () => { ); }); - it('should warn if the render function provided has propTypes or defaultProps attributes', () => { - function renderWithPropTypes(props, ref) { - return null; - } - renderWithPropTypes.propTypes = {}; - + it('should warn if the render function provided has defaultProps attributes', () => { function renderWithDefaultProps(props, ref) { return null; } renderWithDefaultProps.defaultProps = {}; - expect(() => React.forwardRef(renderWithPropTypes)).toErrorDev( - 'forwardRef render functions do not support propTypes or defaultProps. ' + - 'Did you accidentally pass a React component?', - {withoutStack: true}, - ); expect(() => React.forwardRef(renderWithDefaultProps)).toErrorDev( - 'forwardRef render functions do not support propTypes or defaultProps. ' + + 'forwardRef render functions do not support defaultProps. ' + 'Did you accidentally pass a React component?', {withoutStack: true}, );