@samitouri / QOS-React / commits / 23be4102df

Fixed an issue with nested contexts unwinding when server rendering. Issue #12984 (#12985)

* Fixed an issue with nested contexts unwinding when server rendering. GitHub issue #12984 * Fixed an issue with search direction and stricter false checking * Use decrement infix operator * Streamlined existence checks * Streamlined assignment. Removed redundant comment. Use null for array values * Made prettier * Relaxed type checking and improved comment * Improve test coverage

Eric Soderberg committed Jun 11, 2018 at 06:25 UTC 23be4102df273d6ee6d9be42c6d65885d0a914b1
2 files changed +74 -7
packages/react-dom/src/__tests__/ReactDOMServerIntegrationNewContext-test.js
+58
@@ -191,5 +191,63 @@ describe('ReactDOMServerIntegration', () => {
191 expect(e.querySelector('#theme').textContent).toBe('light');
192 expect(e.querySelector('#language').textContent).toBe('english');
193 });
194 +
195 + itRenders('nested context unwinding', async render => {
196 + const Theme = React.createContext('dark');
197 + const Language = React.createContext('french');
198 +
199 + const App = () => (
200 + <div>
201 + <Theme.Provider value="light">
202 + <Language.Provider value="english">
203 + <Theme.Provider value="dark">
204 + <Theme.Consumer>
205 + {theme => <div id="theme1">{theme}</div>}
206 + </Theme.Consumer>
207 + </Theme.Provider>
208 + <Theme.Consumer>
209 + {theme => <div id="theme2">{theme}</div>}
210 + </Theme.Consumer>
211 + <Language.Provider value="sanskrit">
212 + <Theme.Provider value="blue">
213 + <Theme.Provider value="red">
214 + <Language.Consumer>
215 + {() => (
216 + <Language.Provider value="chinese">
217 + <Language.Provider value="hungarian" />
218 + <Language.Consumer>
219 + {language => <div id="language1">{language}</div>}
220 + </Language.Consumer>
221 + </Language.Provider>
222 + )}
223 + </Language.Consumer>
224 + </Theme.Provider>
225 + <Language.Consumer>
226 + {language => (
227 + <React.Fragment>
228 + <Theme.Consumer>
229 + {theme => <div id="theme3">{theme}</div>}
230 + </Theme.Consumer>
231 + <div id="language2">{language}</div>
232 + </React.Fragment>
233 + )}
234 + </Language.Consumer>
235 + </Theme.Provider>
236 + </Language.Provider>
237 + </Language.Provider>
238 + </Theme.Provider>
239 + <Language.Consumer>
240 + {language => <div id="language3">{language}</div>}
241 + </Language.Consumer>
242 + </div>
243 + );
244 + let e = await render(<App />);
245 + expect(e.querySelector('#theme1').textContent).toBe('dark');
246 + expect(e.querySelector('#theme2').textContent).toBe('light');
247 + expect(e.querySelector('#theme3').textContent).toBe('blue');
248 + expect(e.querySelector('#language1').textContent).toBe('chinese');
249 + expect(e.querySelector('#language2').textContent).toBe('sanskrit');
250 + expect(e.querySelector('#language3').textContent).toBe('french');
251 + });
252 });
253 });
packages/react-dom/src/server/ReactPartialRenderer.js
+16 -7
@@ -689,14 +689,23 @@ class ReactDOMServerRenderer {
689 this.providerStack[this.providerIndex] = null;
690 this.providerIndex -= 1;
691 const context: ReactContext<any> = provider.type._context;
692 - if (this.providerIndex < 0) {
693 - context._currentValue = context._defaultValue;
692 +
693 + // Find the closest parent provider of the same type and use its value.
694 + // TODO: it would be nice to avoid this being O(N).
695 + let contextPriorProvider = null;
696 + for (let i = this.providerIndex; i >= 0; i--) {
697 + // We assume this Flow type is correct because of the index check above
698 + // and because pushProvider() enforces the correct type.
699 + const priorProvider: ReactProvider<any> = (this.providerStack[i]: any);
700 + if (priorProvider.type === provider.type) {
701 + contextPriorProvider = priorProvider;
702 + break;
703 + }
704 + }
705 + if (contextPriorProvider !== null) {
706 + context._currentValue = contextPriorProvider.props.value;
707 } else {
695 - // We assume this type is correct because of the index check above.
696 - const previousProvider: ReactProvider<any> = (this.providerStack[
697 - this.providerIndex
698 - ]: any);
699 - context._currentValue = previousProvider.props.value;
708 + context._currentValue = context._defaultValue;
709 }
710 }
711