diff --git a/packages/react-dom/src/__tests__/ReactServerRendering-test.internal.js b/packages/react-dom/src/__tests__/ReactServerRendering-test.internal.js
index 92948d905c477..cc97498cf90b9 100644
--- a/packages/react-dom/src/__tests__/ReactServerRendering-test.internal.js
+++ b/packages/react-dom/src/__tests__/ReactServerRendering-test.internal.js
@@ -667,6 +667,59 @@ describe('ReactDOMServer', () => {
expect(results).toEqual([2, 1, 3, 1]);
});
+ it('renders context API, reentrancy', () => {
+ const Context = React.unstable_createContext(0);
+
+ function Provider(props) {
+ return Context.provide(props.value, props.children);
+ }
+
+ function Consumer(props) {
+ return Context.consume(value => {
+ return 'Result: ' + value;
+ });
+ }
+
+ let reentrantMarkup;
+ function Reentrant() {
+ reentrantMarkup = ReactDOMServer.renderToString(
+ ,
+ );
+ return null;
+ }
+
+ const Indirection = React.Fragment;
+
+ function App(props) {
+ return (
+
+ {props.reentrant && }
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+
+ const markup = ReactDOMServer.renderToString(
+ ,
+ );
+ // Extract the numbers rendered by the consumers
+ const results = markup.match(/\d+/g).map(Number);
+ const reentrantResults = reentrantMarkup.match(/\d+/g).map(Number);
+ expect(results).toEqual([2, 1, 3, 1]);
+ expect(reentrantResults).toEqual([2, 1, 3, 1]);
+ });
+
it('renders components with different batching strategies', () => {
class StaticComponent extends React.Component {
render() {
diff --git a/packages/react-dom/src/server/ReactPartialRenderer.js b/packages/react-dom/src/server/ReactPartialRenderer.js
index 934b1d9b4ac4a..9e6f0c4858539 100644
--- a/packages/react-dom/src/server/ReactPartialRenderer.js
+++ b/packages/react-dom/src/server/ReactPartialRenderer.js
@@ -123,33 +123,6 @@ if (__DEV__) {
};
}
-// Context (new API)
-let providerStack: Array> = []; // Stack of provider objects
-let index = -1;
-
-export function pushProvider(provider: ReactProvider): void {
- index += 1;
- providerStack[index] = provider;
- const context: ReactContext = provider.type.context;
- context.currentProvider = provider;
-}
-
-export function popProvider(provider: ReactProvider): void {
- if (__DEV__) {
- warning(index > -1 && provider === providerStack[index], 'Unexpected pop.');
- }
- // $FlowFixMe - Intentionally unsound
- providerStack[index] = null;
- index -= 1;
- const context: ReactContext = provider.type.context;
- if (index < 0) {
- context.currentProvider = null;
- } else {
- const previousProvider = providerStack[index];
- context.currentProvider = previousProvider;
- }
-}
-
let didWarnDefaultInputValue = false;
let didWarnDefaultChecked = false;
let didWarnDefaultSelectValue = false;
@@ -565,6 +538,9 @@ class ReactDOMServerRenderer {
previousWasTextNode: boolean;
makeStaticMarkup: boolean;
+ providerStack: Array>;
+ providerIndex: number;
+
constructor(children: mixed, makeStaticMarkup: boolean) {
const flatChildren = flattenTopLevelChildren(children);
@@ -586,6 +562,37 @@ class ReactDOMServerRenderer {
this.currentSelectValue = null;
this.previousWasTextNode = false;
this.makeStaticMarkup = makeStaticMarkup;
+
+ // Context (new API)
+ this.providerStack = []; // Stack of provider objects
+ this.providerIndex = -1;
+ }
+
+ pushProvider(provider: ReactProvider): void {
+ this.providerIndex += 1;
+ this.providerStack[this.providerIndex] = provider;
+ const context: ReactContext = provider.type.context;
+ context.currentProvider = provider;
+ }
+
+ popProvider(provider: ReactProvider): void {
+ if (__DEV__) {
+ warning(
+ this.providerIndex > -1 &&
+ provider === this.providerStack[this.providerIndex],
+ 'Unexpected pop.',
+ );
+ }
+ // $FlowFixMe - Intentionally unsound
+ this.providerStack[this.providerIndex] = null;
+ this.providerIndex -= 1;
+ const context: ReactContext = provider.type.context;
+ if (this.providerIndex < 0) {
+ context.currentProvider = null;
+ } else {
+ const previousProvider = this.providerStack[this.providerIndex];
+ context.currentProvider = previousProvider;
+ }
}
read(bytes: number): string | null {
@@ -615,7 +622,7 @@ class ReactDOMServerRenderer {
frame.type.type.$$typeof === REACT_PROVIDER_TYPE
) {
const provider: ReactProvider = (frame.type: any);
- popProvider(provider);
+ this.popProvider(provider);
}
continue;
}
@@ -743,7 +750,7 @@ class ReactDOMServerRenderer {
((frame: any): FrameDev).debugElementStack = [];
}
- pushProvider(provider);
+ this.pushProvider(provider);
this.stack.push(frame);
return '';