diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js
index c3c3aa420db1b..2ebbb9f2d52f5 100644
--- a/packages/react-client/src/__tests__/ReactFlight-test.js
+++ b/packages/react-client/src/__tests__/ReactFlight-test.js
@@ -98,6 +98,19 @@ describe('ReactFlight', () => {
jest.restoreAllMocks();
});
+ function createServerContext(globalName, defaultValue, withStack) {
+ let ctx;
+ expect(() => {
+ ctx = React.createServerContext(globalName, defaultValue);
+ }).toErrorDev(
+ 'Server Context is deprecated and will soon be removed. ' +
+ 'It was never documented and we have found it not to be useful ' +
+ 'enough to warrant the downside it imposes on all apps.',
+ {withoutStack: !withStack},
+ );
+ return ctx;
+ }
+
function clientReference(value) {
return Object.defineProperties(
function () {
@@ -1063,7 +1076,7 @@ describe('ReactFlight', () => {
describe('ServerContext', () => {
// @gate enableServerContext
it('supports basic createServerContext usage', async () => {
- const ServerContext = React.createServerContext(
+ const ServerContext = createServerContext(
'ServerContext',
'hello from server',
);
@@ -1084,10 +1097,7 @@ describe('ReactFlight', () => {
// @gate enableServerContext
it('propagates ServerContext providers in flight', async () => {
- const ServerContext = React.createServerContext(
- 'ServerContext',
- 'default',
- );
+ const ServerContext = createServerContext('ServerContext', 'default');
function Foo() {
return (
@@ -1115,7 +1125,7 @@ describe('ReactFlight', () => {
// @gate enableServerContext
it('errors if you try passing JSX through ServerContext value', () => {
- const ServerContext = React.createServerContext('ServerContext', {
+ const ServerContext = createServerContext('ServerContext', {
foo: {
bar: hi this is default,
},
@@ -1149,10 +1159,7 @@ describe('ReactFlight', () => {
// @gate enableServerContext
it('propagates ServerContext and cleans up the providers in flight', async () => {
- const ServerContext = React.createServerContext(
- 'ServerContext',
- 'default',
- );
+ const ServerContext = createServerContext('ServerContext', 'default');
function Foo() {
return (
@@ -1196,10 +1203,7 @@ describe('ReactFlight', () => {
// @gate enableServerContext
it('propagates ServerContext providers in flight after suspending', async () => {
- const ServerContext = React.createServerContext(
- 'ServerContext',
- 'default',
- );
+ const ServerContext = createServerContext('ServerContext', 'default');
function Foo() {
return (
@@ -1254,10 +1258,7 @@ describe('ReactFlight', () => {
// @gate enableServerContext
it('serializes ServerContext to client', async () => {
- const ServerContext = React.createServerContext(
- 'ServerContext',
- 'default',
- );
+ const ServerContext = createServerContext('ServerContext', 'default');
function ClientBar() {
Scheduler.log('ClientBar');
@@ -1294,16 +1295,13 @@ describe('ReactFlight', () => {
expect(ReactNoop).toMatchRenderedOutput(hi this is server);
expect(() => {
- React.createServerContext('ServerContext', 'default');
+ createServerContext('ServerContext', 'default');
}).toThrow('ServerContext: ServerContext already defined');
});
// @gate enableServerContext
it('takes ServerContext from the client for refetching use cases', async () => {
- const ServerContext = React.createServerContext(
- 'ServerContext',
- 'default',
- );
+ const ServerContext = createServerContext('ServerContext', 'default');
function Bar() {
return {React.useContext(ServerContext)};
}
@@ -1323,7 +1321,7 @@ describe('ReactFlight', () => {
let ServerContext;
function inlineLazyServerContextInitialization() {
if (!ServerContext) {
- ServerContext = React.createServerContext('ServerContext', 'default');
+ ServerContext = createServerContext('ServerContext', 'default');
}
return ServerContext;
}
@@ -1331,7 +1329,7 @@ describe('ReactFlight', () => {
let ClientContext;
function inlineContextInitialization() {
if (!ClientContext) {
- ClientContext = React.createServerContext('ServerContext', 'default');
+ ClientContext = createServerContext('ServerContext', 'default', true);
}
return ClientContext;
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
index 44f6f2e64c349..9b5e2455002af 100644
--- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
@@ -3321,12 +3321,19 @@ describe('ReactDOMFizzServer', () => {
let ServerContext;
function inlineLazyServerContextInitialization() {
if (!ServerContext) {
- ServerContext = React.createServerContext('ServerContext', 'default');
+ expect(() => {
+ ServerContext = React.createServerContext('ServerContext', 'default');
+ }).toErrorDev(
+ 'Server Context is deprecated and will soon be removed. ' +
+ 'It was never documented and we have found it not to be useful ' +
+ 'enough to warrant the downside it imposes on all apps.',
+ );
}
return ServerContext;
}
function Foo() {
+ React.useState(); // component stack generation shouldn't reinit
inlineLazyServerContextInitialization();
return (
<>
@@ -5604,7 +5611,15 @@ describe('ReactDOMFizzServer', () => {
it('basic use(context)', async () => {
const ContextA = React.createContext('default');
const ContextB = React.createContext('B');
- const ServerContext = React.createServerContext('ServerContext', 'default');
+ let ServerContext;
+ expect(() => {
+ ServerContext = React.createServerContext('ServerContext', 'default');
+ }).toErrorDev(
+ 'Server Context is deprecated and will soon be removed. ' +
+ 'It was never documented and we have found it not to be useful ' +
+ 'enough to warrant the downside it imposes on all apps.',
+ {withoutStack: true},
+ );
function Client() {
return use(ContextA) + use(ContextB);
}
diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js
index 9b9697d37eeb2..af474dc148bf7 100644
--- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js
+++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js
@@ -609,8 +609,22 @@ describe('ReactFlightDOMBrowser', () => {
});
it('basic use(context)', async () => {
- const ContextA = React.createServerContext('ContextA', '');
- const ContextB = React.createServerContext('ContextB', 'B');
+ let ContextA;
+ let ContextB;
+ expect(() => {
+ ContextA = React.createServerContext('ContextA', '');
+ ContextB = React.createServerContext('ContextB', 'B');
+ }).toErrorDev(
+ [
+ 'Server Context is deprecated and will soon be removed. ' +
+ 'It was never documented and we have found it not to be useful ' +
+ 'enough to warrant the downside it imposes on all apps.',
+ 'Server Context is deprecated and will soon be removed. ' +
+ 'It was never documented and we have found it not to be useful ' +
+ 'enough to warrant the downside it imposes on all apps.',
+ ],
+ {withoutStack: true},
+ );
function ServerComponent() {
return use(ContextA) + use(ContextB);
diff --git a/packages/react/src/ReactServerContext.js b/packages/react/src/ReactServerContext.js
index 6c1feb6cbecec..3748a05b1262d 100644
--- a/packages/react/src/ReactServerContext.js
+++ b/packages/react/src/ReactServerContext.js
@@ -30,6 +30,13 @@ export function createServerContext(
if (!enableServerContext) {
throw new Error('Not implemented.');
}
+ if (__DEV__) {
+ console.error(
+ 'Server Context is deprecated and will soon be removed. ' +
+ 'It was never documented and we have found it not to be useful ' +
+ 'enough to warrant the downside it imposes on all apps.',
+ );
+ }
let wasDefined = true;
if (!ContextRegistry[globalName]) {
wasDefined = false;
diff --git a/packages/shared/ReactServerContextRegistry.js b/packages/shared/ReactServerContextRegistry.js
index 8b106d890b827..f5bbbae626766 100644
--- a/packages/shared/ReactServerContextRegistry.js
+++ b/packages/shared/ReactServerContextRegistry.js
@@ -9,9 +9,13 @@
import type {ReactServerContext} from 'shared/ReactTypes';
-import {REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED} from 'shared/ReactSymbols';
+import {
+ REACT_PROVIDER_TYPE,
+ REACT_SERVER_CONTEXT_TYPE,
+ REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED,
+} from 'shared/ReactSymbols';
+
import ReactSharedInternals from 'shared/ReactSharedInternals';
-import {createServerContext} from 'react';
const ContextRegistry = ReactSharedInternals.ContextRegistry;
@@ -19,11 +23,55 @@ export function getOrCreateServerContext(
globalName: string,
): ReactServerContext {
if (!ContextRegistry[globalName]) {
- ContextRegistry[globalName] = createServerContext(
- globalName,
- // $FlowFixMe[incompatible-call] function signature doesn't reflect the symbol value
- REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED,
- );
+ const context: ReactServerContext = {
+ $$typeof: REACT_SERVER_CONTEXT_TYPE,
+
+ // As a workaround to support multiple concurrent renderers, we categorize
+ // some renderers as primary and others as secondary. We only expect
+ // there to be two concurrent renderers at most: React Native (primary) and
+ // Fabric (secondary); React DOM (primary) and React ART (secondary).
+ // Secondary renderers store their context values on separate fields.
+ _currentValue: REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED,
+ _currentValue2: REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED,
+
+ _defaultValue: REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED,
+
+ // Used to track how many concurrent renderers this context currently
+ // supports within in a single renderer. Such as parallel server rendering.
+ _threadCount: 0,
+ // These are circular
+ Provider: (null: any),
+ Consumer: (null: any),
+ _globalName: globalName,
+ };
+
+ context.Provider = {
+ $$typeof: REACT_PROVIDER_TYPE,
+ _context: context,
+ };
+
+ if (__DEV__) {
+ let hasWarnedAboutUsingConsumer;
+ context._currentRenderer = null;
+ context._currentRenderer2 = null;
+ Object.defineProperties(
+ context,
+ ({
+ Consumer: {
+ get() {
+ if (!hasWarnedAboutUsingConsumer) {
+ console.error(
+ 'Consumer pattern is not supported by ReactServerContext',
+ );
+ hasWarnedAboutUsingConsumer = true;
+ }
+ return null;
+ },
+ },
+ }: any),
+ );
+ }
+ ContextRegistry[globalName] = context;
}
return ContextRegistry[globalName];
}