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 '';