Skip to content

Commit af28f48

Browse files
authored
Feature flag to disable legacy context for function components (#30319)
While the goal is to remove legacy context completely, I think we can already land the removal of legacy context for function components. I didn't even know this feature existed until reading the code recently. The win is just a couple of property lookups on function renders, but it trims down the API already as the full removal will likely still take a bit more time. www: Starting with enabled test renderer and a feature flag for production rollout. RN: Not enabled, will follow up on this.
1 parent d09484c commit af28f48

15 files changed

+48
-9
lines changed

packages/react-dom/src/__tests__/ReactDOMServerIntegrationLegacyContext-test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ describe('ReactDOMServerIntegration', () => {
8686
});
8787

8888
itRenders('stateless child with context', async render => {
89+
if (gate(flags => flags.disableLegacyContextForFunctionComponents)) {
90+
return;
91+
}
8992
function FunctionChildWithContext(props, context) {
9093
return <div>{context.text}</div>;
9194
}
@@ -118,6 +121,9 @@ describe('ReactDOMServerIntegration', () => {
118121
});
119122

120123
itRenders('stateless child without context', async render => {
124+
if (gate(flags => flags.disableLegacyContextForFunctionComponents)) {
125+
return;
126+
}
121127
function FunctionChildWithoutContext(props, context) {
122128
// this should render blank; context isn't passed to this component.
123129
return <div>{context.text}</div>;
@@ -151,6 +157,9 @@ describe('ReactDOMServerIntegration', () => {
151157
});
152158

153159
itRenders('stateless child with wrong context', async render => {
160+
if (gate(flags => flags.disableLegacyContextForFunctionComponents)) {
161+
return;
162+
}
154163
function FunctionChildWithWrongContext(props, context) {
155164
// this should render blank; context.text isn't passed to this component.
156165
return <div id="statelessWrongChild">{context.text}</div>;
@@ -169,6 +178,9 @@ describe('ReactDOMServerIntegration', () => {
169178
});
170179

171180
itRenders('with context passed through to a grandchild', async render => {
181+
if (gate(flags => flags.disableLegacyContextForFunctionComponents)) {
182+
return;
183+
}
172184
function Grandchild(props, context) {
173185
return <div>{context.text}</div>;
174186
}
@@ -186,6 +198,9 @@ describe('ReactDOMServerIntegration', () => {
186198
});
187199

188200
itRenders('a child context overriding a parent context', async render => {
201+
if (gate(flags => flags.disableLegacyContextForFunctionComponents)) {
202+
return;
203+
}
189204
const Grandchild = (props, context) => {
190205
return <div>{context.text}</div>;
191206
};
@@ -203,6 +218,9 @@ describe('ReactDOMServerIntegration', () => {
203218
});
204219

205220
itRenders('a child context merged with a parent context', async render => {
221+
if (gate(flags => flags.disableLegacyContextForFunctionComponents)) {
222+
return;
223+
}
206224
class Parent extends React.Component {
207225
getChildContext() {
208226
return {text1: 'purple'};
@@ -244,6 +262,9 @@ describe('ReactDOMServerIntegration', () => {
244262
itRenders(
245263
'with a call to componentWillMount before getChildContext',
246264
async render => {
265+
if (gate(flags => flags.disableLegacyContextForFunctionComponents)) {
266+
return;
267+
}
247268
class WillMountContext extends React.Component {
248269
getChildContext() {
249270
return {text: this.state.text};
@@ -270,6 +291,9 @@ describe('ReactDOMServerIntegration', () => {
270291
itRenders(
271292
'if getChildContext exists but childContextTypes is missing with a warning',
272293
async render => {
294+
if (gate(flags => flags.disableLegacyContextForFunctionComponents)) {
295+
return;
296+
}
273297
function HopefulChild(props, context) {
274298
return context.foo || 'nope';
275299
}

packages/react-dom/src/__tests__/ReactFunctionComponent-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ describe('ReactFunctionComponent', () => {
451451
]);
452452
});
453453

454-
// @gate !disableLegacyContext
454+
// @gate !disableLegacyContext && !disableLegacyContextForFunctionComponents
455455
it('should receive context', async () => {
456456
class Parent extends React.Component {
457457
static childContextTypes = {

packages/react-reconciler/src/ReactFiberBeginWork.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ import {
9595
import {
9696
debugRenderPhaseSideEffectsForStrictMode,
9797
disableLegacyContext,
98+
disableLegacyContextForFunctionComponents,
9899
enableProfilerCommitHooks,
99100
enableProfilerTimer,
100101
enableScopeAPI,
@@ -1158,7 +1159,7 @@ function updateFunctionComponent(
11581159
}
11591160

11601161
let context;
1161-
if (!disableLegacyContext) {
1162+
if (!disableLegacyContext && !disableLegacyContextForFunctionComponents) {
11621163
const unmaskedContext = getUnmaskedContext(workInProgress, Component, true);
11631164
context = getMaskedContext(workInProgress, unmaskedContext);
11641165
}

packages/react-reconciler/src/__tests__/ReactIncremental-test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1701,7 +1701,7 @@ describe('ReactIncremental', () => {
17011701
expect(instance.state.n).toEqual(3);
17021702
});
17031703

1704-
// @gate !disableLegacyContext
1704+
// @gate !disableLegacyContext && !disableLegacyContextForFunctionComponents
17051705
it('merges and masks context', async () => {
17061706
class Intl extends React.Component {
17071707
static childContextTypes = {
@@ -1954,7 +1954,7 @@ describe('ReactIncremental', () => {
19541954
]);
19551955
});
19561956

1957-
// @gate !disableLegacyContext
1957+
// @gate !disableLegacyContext && !disableLegacyContextForFunctionComponents
19581958
it('reads context when setState is below the provider', async () => {
19591959
let statefulInst;
19601960

@@ -2046,7 +2046,7 @@ describe('ReactIncremental', () => {
20462046
assertLog([]);
20472047
});
20482048

2049-
// @gate !disableLegacyContext
2049+
// @gate !disableLegacyContext && !disableLegacyContextForFunctionComponents
20502050
it('reads context when setState is above the provider', async () => {
20512051
let statefulInst;
20522052

packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1158,7 +1158,7 @@ describe('ReactIncrementalErrorHandling', () => {
11581158
// because it's used for new context, suspense, and many other features.
11591159
// It has to be tested independently for each feature anyway. So although it
11601160
// doesn't look like it, this test is specific to legacy context.
1161-
// @gate !disableLegacyContext
1161+
// @gate !disableLegacyContext && !disableLegacyContextForFunctionComponents
11621162
it('unwinds the context stack correctly on error', async () => {
11631163
class Provider extends React.Component {
11641164
static childContextTypes = {message: PropTypes.string};

packages/react-reconciler/src/__tests__/ReactUse-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1562,7 +1562,7 @@ describe('ReactUse', () => {
15621562
expect(root).toMatchRenderedOutput('Async!');
15631563
});
15641564

1565-
// @gate !disableLegacyContext
1565+
// @gate !disableLegacyContext && !disableLegacyContextForFunctionComponents
15661566
it('unwrap uncached promises in component that accesses legacy context', async () => {
15671567
class ContextProvider extends React.Component {
15681568
static childContextTypes = {

packages/react-server/src/ReactFizzServer.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ import {
152152
import ReactSharedInternals from 'shared/ReactSharedInternals';
153153
import {
154154
disableLegacyContext,
155+
disableLegacyContextForFunctionComponents,
155156
enableScopeAPI,
156157
enableSuspenseAvoidThisFallbackFizz,
157158
enableCache,
@@ -1654,7 +1655,7 @@ function renderFunctionComponent(
16541655
props: any,
16551656
): void {
16561657
let legacyContext;
1657-
if (!disableLegacyContext) {
1658+
if (!disableLegacyContext && !disableLegacyContextForFunctionComponents) {
16581659
legacyContext = getMaskedContext(Component, task.legacyContext);
16591660
}
16601661
if (__DEV__) {

packages/shared/ReactFeatureFlags.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,14 @@ export const transitionLaneExpirationMs = 5000;
155155
// Renames the internal symbol for elements since they have changed signature/constructor
156156
export const renameElementSymbol = true;
157157

158-
// Removes legacy style context
158+
/**
159+
* Removes legacy style context defined using static `contextTypes` and consumed with static `childContextTypes`.
160+
*/
159161
export const disableLegacyContext = true;
162+
/**
163+
* Removes legacy style context just from function components.
164+
*/
165+
export const disableLegacyContextForFunctionComponents = true;
160166

161167
// Not ready to break experimental yet.
162168
// Modern <StrictMode /> behaviour aligns more with what components

packages/shared/forks/ReactFeatureFlags.native-fb.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const disableCommentsAsDOMContainers = true;
3737
export const disableIEWorkarounds = true;
3838
export const disableInputAttributeSyncing = false;
3939
export const disableLegacyContext = false;
40+
export const disableLegacyContextForFunctionComponents = false;
4041
export const disableLegacyMode = false;
4142
export const disableSchedulerTimeoutInWorkLoop = false;
4243
export const disableStringRefs = true;

packages/shared/forks/ReactFeatureFlags.native-oss.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export const disableDefaultPropsExceptForClasses = true;
2828
export const disableIEWorkarounds = true;
2929
export const disableInputAttributeSyncing = false;
3030
export const disableLegacyContext = true;
31+
export const disableLegacyContextForFunctionComponents = true;
3132
export const disableLegacyMode = false;
3233
export const disableSchedulerTimeoutInWorkLoop = false;
3334
export const disableStringRefs = true;

packages/shared/forks/ReactFeatureFlags.test-renderer.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export const disableStringRefs = true;
9292
export const enableFastJSX = true;
9393
export const disableLegacyMode = true;
9494
export const disableLegacyContext = true;
95+
export const disableLegacyContextForFunctionComponents = true;
9596
export const enableRenderableContext = true;
9697
export const enableReactTestRendererWarning = true;
9798
export const disableDefaultPropsExceptForClasses = true;

packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const disableDefaultPropsExceptForClasses = false;
2020
export const disableIEWorkarounds = true;
2121
export const disableInputAttributeSyncing = false;
2222
export const disableLegacyContext = false;
23+
export const disableLegacyContextForFunctionComponents = false;
2324
export const disableLegacyMode = false;
2425
export const disableSchedulerTimeoutInWorkLoop = false;
2526
export const disableStringRefs = true;

packages/shared/forks/ReactFeatureFlags.test-renderer.www.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export const enableScopeAPI = true;
3232
export const enableCreateEventHandleAPI = false;
3333
export const enableSuspenseCallback = true;
3434
export const disableLegacyContext = false;
35+
export const disableLegacyContextForFunctionComponents = false;
3536
export const enableTrustedTypesIntegration = false;
3637
export const disableTextareaChildren = false;
3738
export const enableSuspenseAvoidThisFallback = true;

packages/shared/forks/ReactFeatureFlags.www-dynamic.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
export const alwaysThrottleRetries = true;
1717
export const disableDefaultPropsExceptForClasses = __VARIANT__;
18+
export const disableLegacyContextForFunctionComponents = __VARIANT__;
1819
export const disableLegacyMode = __VARIANT__;
1920
export const disableSchedulerTimeoutInWorkLoop = __VARIANT__;
2021
export const enableAddPropertiesFastPath = __VARIANT__;

packages/shared/forks/ReactFeatureFlags.www.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const dynamicFeatureFlags: DynamicFeatureFlags = require('ReactFeatureFlags');
1717
export const {
1818
alwaysThrottleRetries,
1919
disableDefaultPropsExceptForClasses,
20+
disableLegacyContextForFunctionComponents,
2021
disableSchedulerTimeoutInWorkLoop,
2122
enableAddPropertiesFastPath,
2223
enableDebugTracing,

0 commit comments

Comments
 (0)