diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index 34f94bffeee..82b33be0f6c 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -49,6 +49,8 @@ src/addons/__tests__/renderSubtreeIntoContainer-test.js * should update context if it changes due to setState * should update context if it changes due to re-render * should render portal with non-context-provider parent +* should get context through non-context-provider parent +* should get context through middle non-context-provider layer src/addons/__tests__/update-test.js * pushes diff --git a/src/addons/__tests__/renderSubtreeIntoContainer-test.js b/src/addons/__tests__/renderSubtreeIntoContainer-test.js index 7ed20edeeaf..95db6c24351 100644 --- a/src/addons/__tests__/renderSubtreeIntoContainer-test.js +++ b/src/addons/__tests__/renderSubtreeIntoContainer-test.js @@ -215,4 +215,86 @@ describe('renderSubtreeIntoContainer', () => { expect(portal.firstChild.innerHTML).toBe('hello'); }); + it('should get context through non-context-provider parent', () => { + var container = document.createElement('div'); + document.body.appendChild(container); + var portal = document.createElement('div'); + + class Parent extends React.Component { + render() { + return ; + } + getChildContext() { + return {value: this.props.value}; + } + static childContextTypes = { + value: React.PropTypes.string.isRequired, + }; + } + + class Middle extends React.Component { + render() { + return null; + } + componentDidMount() { + renderSubtreeIntoContainer(this, , portal); + } + } + + class Child extends React.Component { + static contextTypes = { + value: React.PropTypes.string.isRequired, + }; + render() { + return
{this.context.value}
; + } + } + + ReactDOM.render(, container); + expect(portal.textContent).toBe('foo'); + }); + + it('should get context through middle non-context-provider layer', () => { + var container = document.createElement('div'); + document.body.appendChild(container); + var portal1 = document.createElement('div'); + var portal2 = document.createElement('div'); + + class Parent extends React.Component { + render() { + return null; + } + getChildContext() { + return {value: this.props.value}; + } + componentDidMount() { + renderSubtreeIntoContainer(this, , portal1); + } + static childContextTypes = { + value: React.PropTypes.string.isRequired, + }; + } + + class Middle extends React.Component { + render() { + return null; + } + componentDidMount() { + renderSubtreeIntoContainer(this, , portal2); + } + } + + class Child extends React.Component { + static contextTypes = { + value: React.PropTypes.string.isRequired, + }; + render() { + return
{this.context.value}
; + } + } + + ReactDOM.render(, container); + expect(portal2.textContent).toBe('foo'); + }); + }); diff --git a/src/renderers/shared/fiber/ReactFiberContext.js b/src/renderers/shared/fiber/ReactFiberContext.js index e18e35e2706..6cb171c6729 100644 --- a/src/renderers/shared/fiber/ReactFiberContext.js +++ b/src/renderers/shared/fiber/ReactFiberContext.js @@ -22,6 +22,7 @@ var { } = require('ReactFiberTreeReflection'); var { ClassComponent, + HostContainer, } = require('ReactTypeOfWork'); if (__DEV__) { @@ -137,12 +138,14 @@ exports.findCurrentUnmaskedContext = function(fiber: Fiber) : Object { 'Expected subtree parent to be a mounted class component' ); - let node : ?Fiber = parent; - while (node) { - if (isContextProvider(fiber)) { - return fiber.stateNode.__reactInternalMemoizedMergedChildContext; + let node : Fiber = fiber; + while (node.tag !== HostContainer) { + if (isContextProvider(node)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; } - node = node.return; + const parent = node.return; + invariant(parent, 'Found unexpected detached subtree parent'); + node = parent; } - return emptyObject; + return node.stateNode.context; };