Fix context getting (#8407)
Ben Alpert committed
Nov 28, 2016 at 18:33 UTC
492057c76f9afb8e923d054d2a0b42be14a4ccca
3 files changed
+93
-6
scripts/fiber/tests-passing.txt
+2
@@ -49,6 +49,8 @@ src/addons/__tests__/renderSubtreeIntoContainer-test.js
49
* should update context if it changes due to setState
50
* should update context if it changes due to re-render
51
* should render portal with non-context-provider parent
52
+* should get context through non-context-provider parent
53
+* should get context through middle non-context-provider layer
54
55
src/addons/__tests__/update-test.js
56
* pushes
src/addons/__tests__/renderSubtreeIntoContainer-test.js
+82
@@ -215,4 +215,86 @@ describe('renderSubtreeIntoContainer', () => {
215
expect(portal.firstChild.innerHTML).toBe('hello');
216
});
217
218
+ it('should get context through non-context-provider parent', () => {
219
+ var container = document.createElement('div');
220
+ document.body.appendChild(container);
221
+ var portal = document.createElement('div');
222
+
223
+ class Parent extends React.Component {
224
+ render() {
225
+ return <Middle />;
226
+ }
227
+ getChildContext() {
228
+ return {value: this.props.value};
229
+ }
230
+ static childContextTypes = {
231
+ value: React.PropTypes.string.isRequired,
232
+ };
233
+ }
234
+
235
+ class Middle extends React.Component {
236
+ render() {
237
+ return null;
238
+ }
239
+ componentDidMount() {
240
+ renderSubtreeIntoContainer(this, <Child />, portal);
241
+ }
242
+ }
243
+
244
+ class Child extends React.Component {
245
+ static contextTypes = {
246
+ value: React.PropTypes.string.isRequired,
247
+ };
248
+ render() {
249
+ return <div>{this.context.value}</div>;
250
+ }
251
+ }
252
+
253
+ ReactDOM.render(<Parent value="foo" />, container);
254
+ expect(portal.textContent).toBe('foo');
255
+ });
256
+
257
+ it('should get context through middle non-context-provider layer', () => {
258
+ var container = document.createElement('div');
259
+ document.body.appendChild(container);
260
+ var portal1 = document.createElement('div');
261
+ var portal2 = document.createElement('div');
262
+
263
+ class Parent extends React.Component {
264
+ render() {
265
+ return null;
266
+ }
267
+ getChildContext() {
268
+ return {value: this.props.value};
269
+ }
270
+ componentDidMount() {
271
+ renderSubtreeIntoContainer(this, <Middle />, portal1);
272
+ }
273
+ static childContextTypes = {
274
+ value: React.PropTypes.string.isRequired,
275
+ };
276
+ }
277
+
278
+ class Middle extends React.Component {
279
+ render() {
280
+ return null;
281
+ }
282
+ componentDidMount() {
283
+ renderSubtreeIntoContainer(this, <Child />, portal2);
284
+ }
285
+ }
286
+
287
+ class Child extends React.Component {
288
+ static contextTypes = {
289
+ value: React.PropTypes.string.isRequired,
290
+ };
291
+ render() {
292
+ return <div>{this.context.value}</div>;
293
+ }
294
+ }
295
+
296
+ ReactDOM.render(<Parent value="foo" />, container);
297
+ expect(portal2.textContent).toBe('foo');
298
+ });
299
+
300
});
src/renderers/shared/fiber/ReactFiberContext.js
+9
-6
@@ -22,6 +22,7 @@ var {
22
} = require('ReactFiberTreeReflection');
23
var {
24
ClassComponent,
25
+ HostContainer,
26
} = require('ReactTypeOfWork');
27
28
if (__DEV__) {
@@ -137,12 +138,14 @@ exports.findCurrentUnmaskedContext = function(fiber: Fiber) : Object {
138
'Expected subtree parent to be a mounted class component'
139
);
140
140
- let node : ?Fiber = parent;
141
- while (node) {
142
- if (isContextProvider(fiber)) {
143
- return fiber.stateNode.__reactInternalMemoizedMergedChildContext;
141
+ let node : Fiber = fiber;
142
+ while (node.tag !== HostContainer) {
143
+ if (isContextProvider(node)) {
144
+ return node.stateNode.__reactInternalMemoizedMergedChildContext;
145
}
145
- node = node.return;
146
+ const parent = node.return;
147
+ invariant(parent, 'Found unexpected detached subtree parent');
148
+ node = parent;
149
}
147
- return emptyObject;
150
+ return node.stateNode.context;
151
};