Skip to content

Commit 819e9db

Browse files
committed
Add a feature flag for new behavior
1 parent 0b14570 commit 819e9db

27 files changed

+452
-208
lines changed

packages/react-client/src/ReactFlightReplyClient.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ import type {
1414
RejectedThenable,
1515
ReactCustomFormAction,
1616
} from 'shared/ReactTypes';
17+
import {enableRenderableContext} from 'shared/ReactFeatureFlags';
1718

1819
import {
1920
REACT_ELEMENT_TYPE,
2021
REACT_LAZY_TYPE,
2122
REACT_CONTEXT_TYPE,
23+
REACT_PROVIDER_TYPE,
2224
getIteratorFn,
2325
} from 'shared/ReactSymbols';
2426

@@ -297,7 +299,10 @@ export function processReply(
297299
'React Lazy cannot be passed to Server Functions from the Client.%s',
298300
describeObjectForErrorMessage(parent, key),
299301
);
300-
} else if ((value: any).$$typeof === REACT_CONTEXT_TYPE) {
302+
} else if (
303+
(value: any).$$typeof ===
304+
(enableRenderableContext ? REACT_CONTEXT_TYPE : REACT_PROVIDER_TYPE)
305+
) {
301306
console.error(
302307
'React Context Providers cannot be passed to Server Functions from the Client.%s',
303308
describeObjectForErrorMessage(parent, key),

packages/react-debug-tools/src/ReactDebugHooks.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,11 @@ function setupContexts(contextMap: Map<ReactContext<any>, any>, fiber: Fiber) {
821821
let current: null | Fiber = fiber;
822822
while (current) {
823823
if (current.tag === ContextProvider) {
824-
const context: ReactContext<any> = current.type;
824+
let context: ReactContext<any> = current.type;
825+
if ((context: any)._context !== undefined) {
826+
// Support inspection of pre-19+ providers.
827+
context = (context: any)._context;
828+
}
825829
if (!contextMap.has(context)) {
826830
// Store the current value that we're going to restore later.
827831
contextMap.set(context, context._currentValue);

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

+6
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,12 @@ describe('ReactDOMServerIntegration', () => {
296296
});
297297

298298
itRenders('should treat Context as Context.Provider', async render => {
299+
// The `itRenders` helpers don't work with the gate pragma, so we have to do
300+
// this instead.
301+
if (gate(flags => !flags.enableRenderableContext)) {
302+
return;
303+
}
304+
299305
const Theme = React.createContext('dark');
300306
const Language = React.createContext('french');
301307

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

+1
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,7 @@ describe('ReactDOMServer', () => {
10001000
]);
10011001
});
10021002

1003+
// @gate enableRenderableContext
10031004
it('should warn if an invalid contextType is defined', () => {
10041005
const Context = React.createContext();
10051006
class ComponentA extends React.Component {

packages/react-is/src/ReactIs.js

+28-5
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ import {
1818
REACT_MEMO_TYPE,
1919
REACT_PORTAL_TYPE,
2020
REACT_PROFILER_TYPE,
21+
REACT_PROVIDER_TYPE,
2122
REACT_CONSUMER_TYPE,
2223
REACT_STRICT_MODE_TYPE,
2324
REACT_SUSPENSE_TYPE,
2425
REACT_SUSPENSE_LIST_TYPE,
2526
} from 'shared/ReactSymbols';
2627
import isValidElementType from 'shared/isValidElementType';
28+
import {enableRenderableContext} from 'shared/ReactFeatureFlags';
2729

2830
export function typeOf(object: any): mixed {
2931
if (typeof object === 'object' && object !== null) {
@@ -47,8 +49,17 @@ export function typeOf(object: any): mixed {
4749
case REACT_FORWARD_REF_TYPE:
4850
case REACT_LAZY_TYPE:
4951
case REACT_MEMO_TYPE:
50-
case REACT_CONSUMER_TYPE:
5152
return $$typeofType;
53+
case REACT_CONSUMER_TYPE:
54+
if (enableRenderableContext) {
55+
return $$typeofType;
56+
}
57+
// Fall through
58+
case REACT_PROVIDER_TYPE:
59+
if (!enableRenderableContext) {
60+
return $$typeofType;
61+
}
62+
// Fall through
5263
default:
5364
return $$typeof;
5465
}
@@ -61,8 +72,12 @@ export function typeOf(object: any): mixed {
6172
return undefined;
6273
}
6374

64-
export const ContextConsumer = REACT_CONSUMER_TYPE;
65-
export const ContextProvider = REACT_CONTEXT_TYPE;
75+
export const ContextConsumer: symbol = enableRenderableContext
76+
? REACT_CONSUMER_TYPE
77+
: REACT_CONTEXT_TYPE;
78+
export const ContextProvider: symbol = enableRenderableContext
79+
? REACT_CONTEXT_TYPE
80+
: REACT_PROVIDER_TYPE;
6681
export const Element = REACT_ELEMENT_TYPE;
6782
export const ForwardRef = REACT_FORWARD_REF_TYPE;
6883
export const Fragment = REACT_FRAGMENT_TYPE;
@@ -77,10 +92,18 @@ export const SuspenseList = REACT_SUSPENSE_LIST_TYPE;
7792
export {isValidElementType};
7893

7994
export function isContextConsumer(object: any): boolean {
80-
return typeOf(object) === REACT_CONSUMER_TYPE;
95+
if (enableRenderableContext) {
96+
return typeOf(object) === REACT_CONSUMER_TYPE;
97+
} else {
98+
return typeOf(object) === REACT_CONTEXT_TYPE;
99+
}
81100
}
82101
export function isContextProvider(object: any): boolean {
83-
return typeOf(object) === REACT_CONTEXT_TYPE;
102+
if (enableRenderableContext) {
103+
return typeOf(object) === REACT_CONTEXT_TYPE;
104+
} else {
105+
return typeOf(object) === REACT_PROVIDER_TYPE;
106+
}
84107
}
85108
export function isElement(object: any): boolean {
86109
return (

packages/react-reconciler/src/ReactFiber.js

+20-5
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
enableDebugTracing,
3939
enableFloat,
4040
enableDO_NOT_USE_disableStrictPassiveEffect,
41+
enableRenderableContext,
4142
} from 'shared/ReactFeatureFlags';
4243
import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
4344
import {ConcurrentRoot} from './ReactRootTags';
@@ -94,6 +95,7 @@ import {
9495
REACT_DEBUG_TRACING_MODE_TYPE,
9596
REACT_STRICT_MODE_TYPE,
9697
REACT_PROFILER_TYPE,
98+
REACT_PROVIDER_TYPE,
9799
REACT_CONTEXT_TYPE,
98100
REACT_CONSUMER_TYPE,
99101
REACT_SUSPENSE_TYPE,
@@ -578,13 +580,26 @@ export function createFiberFromTypeAndProps(
578580
default: {
579581
if (typeof type === 'object' && type !== null) {
580582
switch (type.$$typeof) {
583+
case REACT_PROVIDER_TYPE:
584+
if (!enableRenderableContext) {
585+
fiberTag = ContextProvider;
586+
break getTag;
587+
}
588+
// Fall through
581589
case REACT_CONTEXT_TYPE:
582-
fiberTag = ContextProvider;
583-
break getTag;
590+
if (enableRenderableContext) {
591+
fiberTag = ContextProvider;
592+
break getTag;
593+
} else {
594+
fiberTag = ContextConsumer;
595+
break getTag;
596+
}
584597
case REACT_CONSUMER_TYPE:
585-
// This is a consumer
586-
fiberTag = ContextConsumer;
587-
break getTag;
598+
if (enableRenderableContext) {
599+
fiberTag = ContextConsumer;
600+
break getTag;
601+
}
602+
// Fall through
588603
case REACT_FORWARD_REF_TYPE:
589604
fiberTag = ForwardRef;
590605
if (__DEV__) {

packages/react-reconciler/src/ReactFiberBeginWork.js

+25-5
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ import {
110110
enableFormActions,
111111
enableAsyncActions,
112112
enablePostpone,
113+
enableRenderableContext,
113114
} from 'shared/ReactFeatureFlags';
114115
import isArray from 'shared/isArray';
115116
import shallowEqual from 'shared/shallowEqual';
@@ -3528,7 +3529,12 @@ function updateContextProvider(
35283529
workInProgress: Fiber,
35293530
renderLanes: Lanes,
35303531
) {
3531-
const context: ReactContext<any> = workInProgress.type;
3532+
let context: ReactContext<any>;
3533+
if (enableRenderableContext) {
3534+
context = workInProgress.type;
3535+
} else {
3536+
context = workInProgress.type._context;
3537+
}
35323538
const newProps = workInProgress.pendingProps;
35333539
const oldProps = workInProgress.memoizedProps;
35343540

@@ -3590,9 +3596,18 @@ function updateContextConsumer(
35903596
workInProgress: Fiber,
35913597
renderLanes: Lanes,
35923598
) {
3593-
const consumerType: ReactConsumerType<any> = workInProgress.type;
3594-
const context = consumerType._context;
3595-
3599+
let context: ReactContext<any>;
3600+
if (enableRenderableContext) {
3601+
const consumerType: ReactConsumerType<any> = workInProgress.type;
3602+
context = consumerType._context;
3603+
} else {
3604+
context = workInProgress.type;
3605+
if (__DEV__) {
3606+
if ((context: any)._context !== undefined) {
3607+
context = (context: any)._context;
3608+
}
3609+
}
3610+
}
35963611
const newProps = workInProgress.pendingProps;
35973612
const render = newProps.children;
35983613

@@ -3838,7 +3853,12 @@ function attemptEarlyBailoutIfNoScheduledUpdate(
38383853
break;
38393854
case ContextProvider: {
38403855
const newValue = workInProgress.memoizedProps.value;
3841-
const context: ReactContext<any> = workInProgress.type;
3856+
let context: ReactContext<any>;
3857+
if (enableRenderableContext) {
3858+
context = workInProgress.type;
3859+
} else {
3860+
context = workInProgress.type._context;
3861+
}
38423862
pushProvider(workInProgress, context, newValue);
38433863
break;
38443864
}

packages/react-reconciler/src/ReactFiberCompleteWork.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
enableCache,
4040
enableTransitionTracing,
4141
enableFloat,
42+
enableRenderableContext,
4243
passChildrenWhenCloningPersistedNodes,
4344
} from 'shared/ReactFeatureFlags';
4445

@@ -1505,7 +1506,12 @@ function completeWork(
15051506
return null;
15061507
case ContextProvider:
15071508
// Pop provider fiber
1508-
const context: ReactContext<any> = workInProgress.type;
1509+
let context: ReactContext<any>;
1510+
if (enableRenderableContext) {
1511+
context = workInProgress.type;
1512+
} else {
1513+
context = workInProgress.type._context;
1514+
}
15091515
popProvider(context, workInProgress);
15101516
bubbleProperties(workInProgress);
15111517
return null;

packages/react-reconciler/src/ReactFiberNewContext.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import {
4646
enableLazyContextPropagation,
4747
enableFormActions,
4848
enableAsyncActions,
49+
enableRenderableContext,
4950
} from 'shared/ReactFeatureFlags';
5051
import {
5152
getHostTransitionProvider,
@@ -561,7 +562,12 @@ function propagateParentContextChanges(
561562

562563
const oldProps = currentParent.memoizedProps;
563564
if (oldProps !== null) {
564-
const context: ReactContext<any> = parent.type;
565+
let context: ReactContext<any>;
566+
if (enableRenderableContext) {
567+
context = parent.type;
568+
} else {
569+
context = parent.type._context;
570+
}
565571

566572
const newProps = parent.pendingProps;
567573
const newValue = newProps.value;

packages/react-reconciler/src/ReactFiberScope.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ import {
2222
import {isFiberSuspenseAndTimedOut} from './ReactFiberTreeReflection';
2323

2424
import {HostComponent, ScopeComponent, ContextProvider} from './ReactWorkTags';
25-
import {enableScopeAPI} from 'shared/ReactFeatureFlags';
25+
import {
26+
enableScopeAPI,
27+
enableRenderableContext,
28+
} from 'shared/ReactFeatureFlags';
2629

2730
function getSuspenseFallbackChild(fiber: Fiber): Fiber | null {
2831
return ((((fiber.child: any): Fiber).sibling: any): Fiber).child;
@@ -113,7 +116,10 @@ function collectNearestContextValues<T>(
113116
context: ReactContext<T>,
114117
childContextValues: Array<T>,
115118
): void {
116-
if (node.tag === ContextProvider && node.type === context) {
119+
if (
120+
node.tag === ContextProvider &&
121+
(enableRenderableContext ? node.type : node.type._context) === context
122+
) {
117123
const contextValue = node.memoizedProps.value;
118124
childContextValues.push(contextValue);
119125
} else {

packages/react-reconciler/src/ReactFiberUnwindWork.js

+13-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
enableProfilerTimer,
3636
enableCache,
3737
enableTransitionTracing,
38+
enableRenderableContext,
3839
} from 'shared/ReactFeatureFlags';
3940

4041
import {popHostContainer, popHostContext} from './ReactFiberHostContext';
@@ -160,7 +161,12 @@ function unwindWork(
160161
popHostContainer(workInProgress);
161162
return null;
162163
case ContextProvider:
163-
const context: ReactContext<any> = workInProgress.type;
164+
let context: ReactContext<any>;
165+
if (enableRenderableContext) {
166+
context = workInProgress.type;
167+
} else {
168+
context = workInProgress.type._context;
169+
}
164170
popProvider(context, workInProgress);
165171
return null;
166172
case OffscreenComponent:
@@ -250,7 +256,12 @@ function unwindInterruptedWork(
250256
popSuspenseListContext(interruptedWork);
251257
break;
252258
case ContextProvider:
253-
const context: ReactContext<any> = interruptedWork.type;
259+
let context: ReactContext<any>;
260+
if (enableRenderableContext) {
261+
context = interruptedWork.type;
262+
} else {
263+
context = interruptedWork.type._context;
264+
}
254265
popProvider(context, interruptedWork);
255266
break;
256267
case OffscreenComponent:

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

+2
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,7 @@ describe('ReactNewContext', () => {
13391339
);
13401340
});
13411341

1342+
// @gate enableRenderableContext
13421343
it('warns when passed a consumer', async () => {
13431344
const Context = React.createContext(0);
13441345
function Foo() {
@@ -1635,6 +1636,7 @@ Context fuzz tester error! Copy and paste the following line into the test suite
16351636
});
16361637
});
16371638

1639+
// @gate enableRenderableContext
16381640
it('should treat Context as Context.Provider', async () => {
16391641
const BarContext = React.createContext({value: 'bar-initial'});
16401642
expect(BarContext.Provider).toBe(BarContext);

packages/react-reconciler/src/getComponentNameFromFiber.js

+18-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
import type {ReactContext, ReactConsumerType} from 'shared/ReactTypes';
1111
import type {Fiber} from './ReactInternalTypes';
1212

13-
import {enableLegacyHidden} from 'shared/ReactFeatureFlags';
13+
import {
14+
enableLegacyHidden,
15+
enableRenderableContext,
16+
} from 'shared/ReactFeatureFlags';
1417

1518
import {
1619
FunctionComponent,
@@ -68,11 +71,21 @@ export default function getComponentNameFromFiber(fiber: Fiber): string | null {
6871
case CacheComponent:
6972
return 'Cache';
7073
case ContextConsumer:
71-
const consumer: ReactConsumerType<any> = (type: any);
72-
return getContextName(consumer._context) + '.Consumer';
74+
if (enableRenderableContext) {
75+
const consumer: ReactConsumerType<any> = (type: any);
76+
return getContextName(consumer._context) + '.Consumer';
77+
} else {
78+
const context: ReactContext<any> = (type: any);
79+
return getContextName(context) + '.Consumer';
80+
}
7381
case ContextProvider:
74-
const context: ReactContext<any> = (type: any);
75-
return getContextName(context) + '.Provider';
82+
if (enableRenderableContext) {
83+
const context: ReactContext<any> = (type: any);
84+
return getContextName(context) + '.Provider';
85+
} else {
86+
const provider = (type: any);
87+
return getContextName(provider._context) + '.Provider';
88+
}
7689
case DehydratedFragment:
7790
return 'DehydratedFragment';
7891
case ForwardRef:

0 commit comments

Comments
 (0)