From 197184ffb5bf1a740ec0d7c6a542cc7f1f239251 Mon Sep 17 00:00:00 2001 From: Mofei Zhang Date: Fri, 9 Sep 2022 16:48:34 -0400 Subject: [PATCH 1/3] experimental_use(context) for server components and ssr --- .../src/__tests__/ReactDOMFizzServer-test.js | 45 +++++++++++++++++++ .../src/ReactFiberHooks.new.js | 8 +++- .../src/ReactFiberHooks.old.js | 8 +++- .../__tests__/ReactFlightDOMBrowser-test.js | 31 +++++++++++++ packages/react-server/src/ReactFizzHooks.js | 13 +++++- packages/react-server/src/ReactFlightHooks.js | 8 +++- packages/shared/ReactTypes.js | 1 - 7 files changed, 105 insertions(+), 9 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js index 243c7dba8607c..4d821091a2750 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js @@ -5292,6 +5292,51 @@ describe('ReactDOMFizzServer', () => { expect(getVisibleChildren(container)).toEqual('ABC'); }); + // @gate enableUseHook + it('basic use(context)', async () => { + const ContextA = React.createContext('default'); + const ContextB = React.createContext('B'); + const ServerContext = React.createServerContext( + 'ServerContext', + 'default', + ); + function Client() { + return use(ContextA) + use(ContextB); + } + function ServerComponent() { + return use(ServerContext); + } + function Server() { + return ( + + + + ); + } + function App() { + return ( + <> + + + + + + ); + } + + await act(async () => { + const {pipe} = ReactDOMFizzServer.renderToPipeableStream(); + pipe(writable); + }); + expect(getVisibleChildren(container)).toEqual(['AB', 'C']); + + ContextA._currentRenderer = null; + ServerContext._currentRenderer = null; + ReactDOMClient.hydrateRoot(container, ); + expect(Scheduler).toFlushAndYield([]); + expect(getVisibleChildren(container)).toEqual(['AB', 'C']); + }); + // @gate enableUseHook it('use(promise) in multiple components', async () => { const promiseA = Promise.resolve('A'); diff --git a/packages/react-reconciler/src/ReactFiberHooks.new.js b/packages/react-reconciler/src/ReactFiberHooks.new.js index ee3d118a4a5a7..e195bd62a0200 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.new.js +++ b/packages/react-reconciler/src/ReactFiberHooks.new.js @@ -36,7 +36,10 @@ import { enableUseHook, enableUseMemoCacheHook, } from 'shared/ReactFeatureFlags'; -import {REACT_CONTEXT_TYPE} from 'shared/ReactSymbols'; +import { + REACT_CONTEXT_TYPE, + REACT_SERVER_CONTEXT_TYPE, +} from 'shared/ReactSymbols'; import {NoMode, ConcurrentMode, DebugTracingMode} from './ReactTypeOfMode'; import { @@ -772,7 +775,8 @@ function use(usable: Usable): T { } } else if ( usable.$$typeof != null && - usable.$$typeof === REACT_CONTEXT_TYPE + (usable.$$typeof === REACT_CONTEXT_TYPE || + usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) ) { const context: ReactContext = (usable: any); return readContext(context); diff --git a/packages/react-reconciler/src/ReactFiberHooks.old.js b/packages/react-reconciler/src/ReactFiberHooks.old.js index aaa5ed306e42c..c0f0660efe212 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.old.js +++ b/packages/react-reconciler/src/ReactFiberHooks.old.js @@ -36,7 +36,10 @@ import { enableUseHook, enableUseMemoCacheHook, } from 'shared/ReactFeatureFlags'; -import {REACT_CONTEXT_TYPE} from 'shared/ReactSymbols'; +import { + REACT_CONTEXT_TYPE, + REACT_SERVER_CONTEXT_TYPE, +} from 'shared/ReactSymbols'; import {NoMode, ConcurrentMode, DebugTracingMode} from './ReactTypeOfMode'; import { @@ -772,7 +775,8 @@ function use(usable: Usable): T { } } else if ( usable.$$typeof != null && - usable.$$typeof === REACT_CONTEXT_TYPE + (usable.$$typeof === REACT_CONTEXT_TYPE || + usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) ) { const context: ReactContext = (usable: any); return readContext(context); 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 1b59c72ab3e48..2a3d5cefa1bca 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js @@ -594,6 +594,37 @@ describe('ReactFlightDOMBrowser', () => { expect(container.innerHTML).toBe('ABC'); }); + // @gate enableUseHook + it('basic use(context)', async () => { + const ContextA = React.createServerContext('ContextA', ''); + const ContextB = React.createServerContext('ContextB', 'B'); + + function ServerComponent() { + return use(ContextA) + use(ContextB); + } + function Server() { + return ( + + + + ); + } + const stream = ReactServerDOMWriter.renderToReadableStream(); + const response = ReactServerDOMReader.createFromReadableStream(stream); + + function Client() { + return response.readRoot(); + } + + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + await act(async () => { + ContextA._currentRenderer = null; + root.render(); + }); + expect(container.innerHTML).toBe('AB'); + }); + // @gate enableUseHook it('use(promise) in multiple components', async () => { function Child({prefix}) { diff --git a/packages/react-server/src/ReactFizzHooks.js b/packages/react-server/src/ReactFizzHooks.js index 02072fabd3f37..a5a485db70189 100644 --- a/packages/react-server/src/ReactFizzHooks.js +++ b/packages/react-server/src/ReactFizzHooks.js @@ -39,6 +39,10 @@ import { enableUseMemoCacheHook, } from 'shared/ReactFeatureFlags'; import is from 'shared/objectIs'; +import { + REACT_SERVER_CONTEXT_TYPE, + REACT_CONTEXT_TYPE, +} from 'shared/ReactSymbols'; type BasicStateAction = (S => S) | S; type Dispatch = A => void; @@ -616,8 +620,13 @@ function use(usable: Usable): T { } } } - } else { - // TODO: Add support for Context + } else if ( + usable.$$typeof != null && + (usable.$$typeof === REACT_CONTEXT_TYPE || + usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) + ) { + const context: ReactContext = (usable: any); + return readContext(context); } } diff --git a/packages/react-server/src/ReactFlightHooks.js b/packages/react-server/src/ReactFlightHooks.js index f4784c82e1cf1..79dfee587116c 100644 --- a/packages/react-server/src/ReactFlightHooks.js +++ b/packages/react-server/src/ReactFlightHooks.js @@ -200,8 +200,12 @@ function use(usable: Usable): T { } } } - } else { - // TODO: Add support for Context + } else if ( + usable.$$typeof != null && + usable.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + const context: ReactServerContext = (usable: any); + return readContext(context); } } diff --git a/packages/shared/ReactTypes.js b/packages/shared/ReactTypes.js index 9ea076b15f9e7..2832535c87c95 100644 --- a/packages/shared/ReactTypes.js +++ b/packages/shared/ReactTypes.js @@ -213,5 +213,4 @@ export type StartTransitionOptions = {| name?: string, |}; -// TODO: Add Context support export type Usable = Thenable | ReactContext; From 92e196c06124827da091b3c9feca2275914988a7 Mon Sep 17 00:00:00 2001 From: Mofei Zhang Date: Fri, 9 Sep 2022 17:53:30 -0400 Subject: [PATCH 2/3] [nit] Remove redundant 20517typeof check --- packages/react-reconciler/src/ReactFiberHooks.new.js | 5 ++--- packages/react-reconciler/src/ReactFiberHooks.old.js | 5 ++--- packages/react-server/src/ReactFizzHooks.js | 5 ++--- packages/react-server/src/ReactFlightHooks.js | 5 +---- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberHooks.new.js b/packages/react-reconciler/src/ReactFiberHooks.new.js index e195bd62a0200..6ca089ff2d0a8 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.new.js +++ b/packages/react-reconciler/src/ReactFiberHooks.new.js @@ -774,9 +774,8 @@ function use(usable: Usable): T { } } } else if ( - usable.$$typeof != null && - (usable.$$typeof === REACT_CONTEXT_TYPE || - usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) + usable.$$typeof === REACT_CONTEXT_TYPE || + usable.$$typeof === REACT_SERVER_CONTEXT_TYPE ) { const context: ReactContext = (usable: any); return readContext(context); diff --git a/packages/react-reconciler/src/ReactFiberHooks.old.js b/packages/react-reconciler/src/ReactFiberHooks.old.js index c0f0660efe212..133dc8d5dd6eb 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.old.js +++ b/packages/react-reconciler/src/ReactFiberHooks.old.js @@ -774,9 +774,8 @@ function use(usable: Usable): T { } } } else if ( - usable.$$typeof != null && - (usable.$$typeof === REACT_CONTEXT_TYPE || - usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) + usable.$$typeof === REACT_CONTEXT_TYPE || + usable.$$typeof === REACT_SERVER_CONTEXT_TYPE ) { const context: ReactContext = (usable: any); return readContext(context); diff --git a/packages/react-server/src/ReactFizzHooks.js b/packages/react-server/src/ReactFizzHooks.js index a5a485db70189..b330605260afd 100644 --- a/packages/react-server/src/ReactFizzHooks.js +++ b/packages/react-server/src/ReactFizzHooks.js @@ -621,9 +621,8 @@ function use(usable: Usable): T { } } } else if ( - usable.$$typeof != null && - (usable.$$typeof === REACT_CONTEXT_TYPE || - usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) + usable.$$typeof === REACT_CONTEXT_TYPE || + usable.$$typeof === REACT_SERVER_CONTEXT_TYPE ) { const context: ReactContext = (usable: any); return readContext(context); diff --git a/packages/react-server/src/ReactFlightHooks.js b/packages/react-server/src/ReactFlightHooks.js index 79dfee587116c..dfb234b15ad27 100644 --- a/packages/react-server/src/ReactFlightHooks.js +++ b/packages/react-server/src/ReactFlightHooks.js @@ -200,10 +200,7 @@ function use(usable: Usable): T { } } } - } else if ( - usable.$$typeof != null && - usable.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { + } else if (usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) { const context: ReactServerContext = (usable: any); return readContext(context); } From 0233f2ce9031ee92b5567b9bac15c6bad9fd29cb Mon Sep 17 00:00:00 2001 From: Mofei Zhang Date: Fri, 9 Sep 2022 20:58:50 -0400 Subject: [PATCH 3/3] add comments to test case --- packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js | 3 +++ .../src/__tests__/ReactFlightDOMBrowser-test.js | 3 +++ 2 files changed, 6 insertions(+) diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js index 4d821091a2750..4d8e677e03739 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js @@ -5330,6 +5330,9 @@ describe('ReactDOMFizzServer', () => { }); expect(getVisibleChildren(container)).toEqual(['AB', 'C']); + // Hydration uses a different renderer runtime (Fiber instead of Fizz). + // We reset _currentRenderer here to not trigger a warning about multiple + // renderers concurrently using these contexts ContextA._currentRenderer = null; ServerContext._currentRenderer = null; ReactDOMClient.hydrateRoot(container, ); 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 2a3d5cefa1bca..f477bba451a6e 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js @@ -619,6 +619,9 @@ describe('ReactFlightDOMBrowser', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); await act(async () => { + // Client uses a different renderer. + // We reset _currentRenderer here to not trigger a warning about multiple + // renderers concurrently using this context ContextA._currentRenderer = null; root.render(); });