From f610b741fa5426da44747d6d7549494acba6f830 Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Tue, 12 Mar 2024 15:13:44 -0400 Subject: [PATCH] Disable legacy context This enables the `disableLegacyContext` flag for web and React Native. --- .../src/__tests__/editing-test.js | 5 +++ .../src/__tests__/profilingCache-test.js | 29 +++++++++++------ .../__tests__/ReactComponentLifeCycle-test.js | 1 + .../ReactErrorBoundaries-test.internal.js | 31 ++++++++++++------- ...eactLegacyErrorBoundaries-test.internal.js | 12 +++++-- ...tIncrementalErrorHandling-test.internal.js | 8 +++++ packages/shared/ReactFeatureFlags.js | 4 +-- .../forks/ReactFeatureFlags.test-renderer.js | 2 +- 8 files changed, 66 insertions(+), 26 deletions(-) diff --git a/packages/react-devtools-shared/src/__tests__/editing-test.js b/packages/react-devtools-shared/src/__tests__/editing-test.js index cece83ba708aa..750e13e38d5d4 100644 --- a/packages/react-devtools-shared/src/__tests__/editing-test.js +++ b/packages/react-devtools-shared/src/__tests__/editing-test.js @@ -934,6 +934,7 @@ describe('editing interface', () => { } // @reactVersion >= 16.9 + // @gate !disableLegacyContext it('should have editable values', async () => { await mountTestApp(); @@ -983,6 +984,7 @@ describe('editing interface', () => { }); // @reactVersion >= 16.9 + // @gate !disableLegacyContext // Tests the combination of older frontend (DevTools UI) with newer backend (embedded within a renderer). it('should still support overriding context values with legacy backend methods', async () => { await mountTestApp(); @@ -1014,6 +1016,7 @@ describe('editing interface', () => { }); // @reactVersion >= 16.9 + // @gate !disableLegacyContext it('should have editable paths', async () => { await mountTestApp(); @@ -1055,6 +1058,7 @@ describe('editing interface', () => { }); // @reactVersion >= 16.9 + // @gate !disableLegacyContext it('should enable adding new object properties and array values', async () => { await mountTestApp(); @@ -1109,6 +1113,7 @@ describe('editing interface', () => { }); // @reactVersion >= 16.9 + // @gate !disableLegacyContext it('should have deletable keys', async () => { await mountTestApp(); diff --git a/packages/react-devtools-shared/src/__tests__/profilingCache-test.js b/packages/react-devtools-shared/src/__tests__/profilingCache-test.js index 6c9e1bb30c89a..dbb2c1bee1467 100644 --- a/packages/react-devtools-shared/src/__tests__/profilingCache-test.js +++ b/packages/react-devtools-shared/src/__tests__/profilingCache-test.js @@ -411,6 +411,21 @@ describe('ProfilingCache', () => { }, } `); + + if (gate(flags => !flags.disableLegacyContext)) { + expect(changeDescriptions[1].get(6).context).toEqual(['count']); + expect(changeDescriptions[1].get(7).props).toEqual(['count']); + expect(changeDescriptions[2].get(6).context).toEqual([]); + expect(changeDescriptions[3].get(6).context).toEqual([]); + expect(changeDescriptions[4].get(6).context).toEqual([]); + + changeDescriptions[1].get(6).context = null; + changeDescriptions[1].get(7).props = []; + changeDescriptions[2].get(6).context = null; + changeDescriptions[3].get(6).context = null; + changeDescriptions[4].get(6).context = null; + } + expect(changeDescriptions[1]).toMatchInlineSnapshot(` Map { 5 => { @@ -436,15 +451,11 @@ describe('ProfilingCache', () => { "didHooksChange": false, "hooks": [], "isFirstMount": false, - "props": [ - "count", - ], + "props": [], "state": null, }, 6 => { - "context": [ - "count", - ], + "context": null, "didHooksChange": false, "hooks": null, "isFirstMount": false, @@ -490,7 +501,7 @@ describe('ProfilingCache', () => { "state": null, }, 6 => { - "context": [], + "context": null, "didHooksChange": false, "hooks": null, "isFirstMount": false, @@ -536,7 +547,7 @@ describe('ProfilingCache', () => { "state": null, }, 6 => { - "context": [], + "context": null, "didHooksChange": false, "hooks": null, "isFirstMount": false, @@ -583,7 +594,7 @@ describe('ProfilingCache', () => { "state": null, }, 6 => { - "context": [], + "context": null, "didHooksChange": false, "hooks": null, "isFirstMount": false, diff --git a/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js b/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js index 8523e2784872f..9fc7498c10730 100644 --- a/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js +++ b/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js @@ -1112,6 +1112,7 @@ describe('ReactComponentLifeCycle', () => { }); if (!require('shared/ReactFeatureFlags').disableModulePatternComponents) { + // @gate !disableLegacyContext it('calls effects on module-pattern component', async () => { const log = []; diff --git a/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js b/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js index 284cb0599aded..e0176d80ddd84 100644 --- a/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js @@ -880,7 +880,6 @@ describe('ReactErrorBoundaries', () => { }); // @gate !disableModulePatternComponents - // @gate !disableLegacyContext it('renders an error state if module-style context provider throws in componentWillMount', async () => { function BrokenComponentWillMountWithContext() { return { @@ -901,23 +900,31 @@ describe('ReactErrorBoundaries', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect( - async () => - await act(async () => { - root.render( - - - , - ); - }), - ).toErrorDev( + + await expect(async () => { + await act(() => { + root.render( + + + , + ); + }); + }).toErrorDev([ 'Warning: The component appears to be a function component that ' + 'returns a class instance. ' + 'Change BrokenComponentWillMountWithContext to a class that extends React.Component instead. ' + "If you can't use a class try assigning the prototype on the function as a workaround. " + '`BrokenComponentWillMountWithContext.prototype = React.Component.prototype`. ' + "Don't use an arrow function since it cannot be called with `new` by React.", - ); + ...gate(flags => + flags.disableLegacyContext + ? [ + 'Warning: BrokenComponentWillMountWithContext uses the legacy childContextTypes API which is no longer supported. Use React.createContext() instead.', + 'Warning: BrokenComponentWillMountWithContext uses the legacy childContextTypes API which is no longer supported. Use React.createContext() instead.', + ] + : [], + ), + ]); expect(container.firstChild.textContent).toBe('Caught an error: Hello.'); }); diff --git a/packages/react-dom/src/__tests__/ReactLegacyErrorBoundaries-test.internal.js b/packages/react-dom/src/__tests__/ReactLegacyErrorBoundaries-test.internal.js index bed800fb1da73..e5a2c52ad3ea2 100644 --- a/packages/react-dom/src/__tests__/ReactLegacyErrorBoundaries-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactLegacyErrorBoundaries-test.internal.js @@ -859,14 +859,22 @@ describe('ReactLegacyErrorBoundaries', () => { , container, ), - ).toErrorDev( + ).toErrorDev([ 'Warning: The component appears to be a function component that ' + 'returns a class instance. ' + 'Change BrokenComponentWillMountWithContext to a class that extends React.Component instead. ' + "If you can't use a class try assigning the prototype on the function as a workaround. " + '`BrokenComponentWillMountWithContext.prototype = React.Component.prototype`. ' + "Don't use an arrow function since it cannot be called with `new` by React.", - ); + ...gate(flags => + flags.disableLegacyContext + ? [ + 'Warning: BrokenComponentWillMountWithContext uses the legacy childContextTypes API which is no longer supported. Use React.createContext() instead.', + 'Warning: BrokenComponentWillMountWithContext uses the legacy childContextTypes API which is no longer supported. Use React.createContext() instead.', + ] + : [], + ), + ]); expect(container.firstChild.textContent).toBe('Caught an error: Hello.'); }); } diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js index 1613f1e048ec7..763a2fc9ca204 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js @@ -1782,6 +1782,14 @@ describe('ReactIncrementalErrorHandling', () => { "If you can't use a class try assigning the prototype on the function as a workaround. " + '`Provider.prototype = React.Component.prototype`. ' + "Don't use an arrow function since it cannot be called with `new` by React.", + ...gate(flags => + flags.disableLegacyContext + ? [ + 'Warning: Provider uses the legacy childContextTypes API which is no longer supported. Use React.createContext() instead.', + 'Warning: Provider uses the legacy childContextTypes API which is no longer supported. Use React.createContext() instead.', + ] + : [], + ), ]); }); diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index cdd57a308380c..0e88a9674dcf8 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -140,8 +140,8 @@ export const transitionLaneExpirationMs = 5000; // ----------------------------------------------------------------------------- const __NEXT_MAJOR__ = __EXPERIMENTAL__; -// Not ready to break experimental yet. -export const disableLegacyContext = false; +// Removes legacy style context +export const disableLegacyContext = __NEXT_MAJOR__; // Not ready to break experimental yet. // Disable javascript: URL strings in href for XSS protection. diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 981f7bf10572f..fc05a456821f4 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -33,7 +33,6 @@ export const disableIEWorkarounds = true; export const enableScopeAPI = false; export const enableCreateEventHandleAPI = false; export const enableSuspenseCallback = false; -export const disableLegacyContext = false; export const enableTrustedTypesIntegration = false; export const disableTextareaChildren = false; export const disableModulePatternComponents = false; @@ -100,6 +99,7 @@ export const disableStringRefs = __NEXT_MAJOR__; export const enableReactTestRendererWarning = false; export const enableBigIntSupport = __NEXT_MAJOR__; export const disableLegacyMode = __NEXT_MAJOR__; +export const disableLegacyContext = __NEXT_MAJOR__; // Flow magic to verify the exports of this file match the original version. ((((null: any): ExportsType): FeatureFlagsType): ExportsType);