diff --git a/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js b/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js index d3b8926ecd3ea..2c1859eac3777 100644 --- a/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js @@ -13,6 +13,7 @@ let PropTypes; let React; let ReactDOMClient; let act; +let assertConsoleErrorDev; function FunctionComponent(props) { return
{props.name}
; @@ -24,7 +25,7 @@ describe('ReactFunctionComponent', () => { PropTypes = require('prop-types'); React = require('react'); ReactDOMClient = require('react-dom/client'); - act = require('internal-test-utils').act; + ({act, assertConsoleErrorDev} = require('internal-test-utils')); }); it('should render stateless component', async () => { @@ -109,6 +110,10 @@ describe('ReactFunctionComponent', () => { root.render(); }); + assertConsoleErrorDev([ + 'Child uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.', + ]); + expect(el.textContent).toBe('test'); await act(() => { @@ -472,6 +477,9 @@ describe('ReactFunctionComponent', () => { await act(() => { root.render(); }); + assertConsoleErrorDev([ + 'Child uses the legacy contextTypes API which will be removed soon. Use React.createContext() with React.useContext() instead.', + ]); expect(el.textContent).toBe('en'); }); diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 5c759d9a52cf1..9625d5ae89c83 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -1130,12 +1130,20 @@ function updateFunctionComponent( // in updateFuntionComponent but only on mount validateFunctionComponentInDev(workInProgress, workInProgress.type); - if (disableLegacyContext && Component.contextTypes) { - console.error( - '%s uses the legacy contextTypes API which was removed in React 19. ' + - 'Use React.createContext() with React.useContext() instead.', - getComponentNameFromType(Component) || 'Unknown', - ); + if (Component.contextTypes) { + if (disableLegacyContext) { + console.error( + '%s uses the legacy contextTypes API which was removed in React 19. ' + + 'Use React.createContext() with React.useContext() instead.', + getComponentNameFromType(Component) || 'Unknown', + ); + } else { + console.error( + '%s uses the legacy contextTypes API which will be removed soon. ' + + 'Use React.createContext() with React.useContext() instead.', + getComponentNameFromType(Component) || 'Unknown', + ); + } } } } diff --git a/packages/react-reconciler/src/ReactFiberClassComponent.js b/packages/react-reconciler/src/ReactFiberClassComponent.js index 4f7ef8530a908..4189546a0815a 100644 --- a/packages/react-reconciler/src/ReactFiberClassComponent.js +++ b/packages/react-reconciler/src/ReactFiberClassComponent.js @@ -426,6 +426,22 @@ function checkClassInstance(workInProgress: Fiber, ctor: any, newProps: any) { name, ); } + if (ctor.childContextTypes && !didWarnAboutChildContextTypes.has(ctor)) { + didWarnAboutChildContextTypes.add(ctor); + console.error( + '%s uses the legacy childContextTypes API which will soon be removed. ' + + 'Use React.createContext() instead.', + name, + ); + } + if (ctor.contextTypes && !didWarnAboutContextTypes.has(ctor)) { + didWarnAboutContextTypes.add(ctor); + console.error( + '%s uses the legacy contextTypes API which will soon be removed. ' + + 'Use React.createContext() with static contextType instead.', + name, + ); + } } if (typeof instance.componentShouldUpdate === 'function') { diff --git a/packages/react-server/src/ReactFizzClassComponent.js b/packages/react-server/src/ReactFizzClassComponent.js index 6ef87f100b57d..8fa17bbdc41fd 100644 --- a/packages/react-server/src/ReactFizzClassComponent.js +++ b/packages/react-server/src/ReactFizzClassComponent.js @@ -403,6 +403,22 @@ function checkClassInstance(instance: any, ctor: any, newProps: any) { name, ); } + if (ctor.childContextTypes && !didWarnAboutChildContextTypes.has(ctor)) { + didWarnAboutChildContextTypes.add(ctor); + console.error( + '%s uses the legacy childContextTypes API which will soon be removed. ' + + 'Use React.createContext() instead.', + name, + ); + } + if (ctor.contextTypes && !didWarnAboutContextTypes.has(ctor)) { + didWarnAboutContextTypes.add(ctor); + console.error( + '%s uses the legacy contextTypes API which will soon be removed. ' + + 'Use React.createContext() with static contextType instead.', + name, + ); + } } if (typeof instance.componentShouldUpdate === 'function') { diff --git a/packages/react/src/__tests__/ReactES6Class-test.js b/packages/react/src/__tests__/ReactES6Class-test.js index 769bf5b9a5daf..3ac0b18e8e753 100644 --- a/packages/react/src/__tests__/ReactES6Class-test.js +++ b/packages/react/src/__tests__/ReactES6Class-test.js @@ -13,6 +13,7 @@ let PropTypes; let React; let ReactDOM; let ReactDOMClient; +let assertConsoleErrorDev; describe('ReactES6Class', () => { let container; @@ -30,6 +31,7 @@ describe('ReactES6Class', () => { React = require('react'); ReactDOM = require('react-dom'); ReactDOMClient = require('react-dom/client'); + ({assertConsoleErrorDev} = require('internal-test-utils')); container = document.createElement('div'); root = ReactDOMClient.createRoot(container); attachedListener = null; @@ -287,6 +289,11 @@ describe('ReactES6Class', () => { className: PropTypes.string, }; runTest(, 'SPAN', 'foo'); + + assertConsoleErrorDev([ + 'Outer uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.', + 'Foo uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.', + ]); }); } @@ -579,6 +586,10 @@ describe('ReactES6Class', () => { } Foo.childContextTypes = {bar: PropTypes.string}; runTest(, 'DIV', 'bar-through-context'); + assertConsoleErrorDev([ + 'Foo uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.', + 'Bar uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.', + ]); }); }