diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationNewContext-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationNewContext-test.js
index c3c08eb6bf773..2bcece083a4b8 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationNewContext-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationNewContext-test.js
@@ -191,5 +191,63 @@ describe('ReactDOMServerIntegration', () => {
expect(e.querySelector('#theme').textContent).toBe('light');
expect(e.querySelector('#language').textContent).toBe('english');
});
+
+ itRenders('nested context unwinding', async render => {
+ const Theme = React.createContext('dark');
+ const Language = React.createContext('french');
+
+ const App = () => (
+
+
+
+
+
+ {theme => {theme}
}
+
+
+
+ {theme => {theme}
}
+
+
+
+
+
+ {() => (
+
+
+
+ {language => {language}
}
+
+
+ )}
+
+
+
+ {language => (
+
+
+ {theme => {theme}
}
+
+ {language}
+
+ )}
+
+
+
+
+
+
+ {language => {language}
}
+
+
+ );
+ let e = await render();
+ expect(e.querySelector('#theme1').textContent).toBe('dark');
+ expect(e.querySelector('#theme2').textContent).toBe('light');
+ expect(e.querySelector('#theme3').textContent).toBe('blue');
+ expect(e.querySelector('#language1').textContent).toBe('chinese');
+ expect(e.querySelector('#language2').textContent).toBe('sanskrit');
+ expect(e.querySelector('#language3').textContent).toBe('french');
+ });
});
});
diff --git a/packages/react-dom/src/server/ReactPartialRenderer.js b/packages/react-dom/src/server/ReactPartialRenderer.js
index 59ea170b938d5..f33ffd239eb2a 100644
--- a/packages/react-dom/src/server/ReactPartialRenderer.js
+++ b/packages/react-dom/src/server/ReactPartialRenderer.js
@@ -689,14 +689,23 @@ class ReactDOMServerRenderer {
this.providerStack[this.providerIndex] = null;
this.providerIndex -= 1;
const context: ReactContext = provider.type._context;
- if (this.providerIndex < 0) {
- context._currentValue = context._defaultValue;
+
+ // Find the closest parent provider of the same type and use its value.
+ // TODO: it would be nice to avoid this being O(N).
+ let contextPriorProvider = null;
+ for (let i = this.providerIndex; i >= 0; i--) {
+ // We assume this Flow type is correct because of the index check above
+ // and because pushProvider() enforces the correct type.
+ const priorProvider: ReactProvider = (this.providerStack[i]: any);
+ if (priorProvider.type === provider.type) {
+ contextPriorProvider = priorProvider;
+ break;
+ }
+ }
+ if (contextPriorProvider !== null) {
+ context._currentValue = contextPriorProvider.props.value;
} else {
- // We assume this type is correct because of the index check above.
- const previousProvider: ReactProvider = (this.providerStack[
- this.providerIndex
- ]: any);
- context._currentValue = previousProvider.props.value;
+ context._currentValue = context._defaultValue;
}
}