diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index 40d2350c562df..6902deccdec4c 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -1565,6 +1565,7 @@ src/renderers/shared/shared/__tests__/ReactUpdates-test.js * does not update one component twice in a batch (#6371) * unstable_batchedUpdates should return value from a callback * unmounts and remounts a root in the same batch +* handles reentrant mounting in synchronous mode src/renderers/shared/shared/__tests__/refs-destruction-test.js * should remove refs when destroying the parent diff --git a/src/renderers/art/ReactARTFiber.js b/src/renderers/art/ReactARTFiber.js index 89bbc61fda427..6244642a8432d 100644 --- a/src/renderers/art/ReactARTFiber.js +++ b/src/renderers/art/ReactARTFiber.js @@ -328,9 +328,10 @@ class Surface extends Component { this._surface = Mode.Surface(+width, +height, this._tagRef); - this._mountNode = ARTRenderer.mountContainer( + this._mountNode = ARTRenderer.createContainer(this._surface); + ARTRenderer.updateContainer( this.props.children, - this._surface, + this._mountNode, this, ); } diff --git a/src/renderers/dom/fiber/ReactDOMFiber.js b/src/renderers/dom/fiber/ReactDOMFiber.js index 9475f24ee2b40..3b6330db66562 100644 --- a/src/renderers/dom/fiber/ReactDOMFiber.js +++ b/src/renderers/dom/fiber/ReactDOMFiber.js @@ -289,16 +289,15 @@ function renderSubtreeIntoContainer(parentComponent : ?ReactComponent, rootID : string, callback : ?Function) { - if (!roots.has(rootID)) { + let root = roots.get(rootID); + if (!root) { const container = { rootID: rootID, children: [] }; rootContainers.set(rootID, container); - const root = NoopRenderer.mountContainer(element, container, null, callback); + root = NoopRenderer.createContainer(container); roots.set(rootID, root); - } else { - const root = roots.get(rootID); - if (root) { - NoopRenderer.updateContainer(element, root, null, callback); - } } + NoopRenderer.updateContainer(element, root, null, callback); }, unmountRootWithID(rootID : string) { diff --git a/src/renderers/shared/fiber/ReactFiberBeginWork.js b/src/renderers/shared/fiber/ReactFiberBeginWork.js index ce503be9ec947..17e7a4cd413cc 100644 --- a/src/renderers/shared/fiber/ReactFiberBeginWork.js +++ b/src/renderers/shared/fiber/ReactFiberBeginWork.js @@ -274,7 +274,8 @@ module.exports = function( root.pendingContext, root.pendingContext !== root.context ); - } else { + } else if (root.context) { + // Should always be set pushTopLevelContextObject( workInProgress, root.context, diff --git a/src/renderers/shared/fiber/ReactFiberReconciler.js b/src/renderers/shared/fiber/ReactFiberReconciler.js index 2b63d3c5f9253..35fe52d22f7c2 100644 --- a/src/renderers/shared/fiber/ReactFiberReconciler.js +++ b/src/renderers/shared/fiber/ReactFiberReconciler.js @@ -75,7 +75,7 @@ export type HostConfig = { }; export type Reconciler = { - mountContainer(element : ReactNodeList, containerInfo : C, parentComponent : ?ReactComponent) : OpaqueNode, + createContainer(containerInfo : C) : OpaqueNode, updateContainer(element : ReactNodeList, container : OpaqueNode, parentComponent : ?ReactComponent) : void, performWithPriority(priorityLevel : PriorityLevel, fn : Function) : void, /* eslint-disable no-undef */ @@ -119,17 +119,10 @@ module.exports = function(config : HostConfig, callback: ?Function) : OpaqueNode { - const context = getContextForSubtree(parentComponent); - const root = createFiberRoot(containerInfo, context); + createContainer(containerInfo : C) : OpaqueNode { + const root = createFiberRoot(containerInfo); const current = root.current; - scheduleTopLevelUpdate(current, element, callback); - - if (__DEV__ && ReactFiberInstrumentation.debugTool) { - ReactFiberInstrumentation.debugTool.onMountContainer(root); - } - // It may seem strange that we don't return the root here, but that will // allow us to have containers that are in the middle of the tree instead // of being roots. @@ -141,19 +134,26 @@ module.exports = function(config : HostConfig { }); expect(container.textContent).toBe('b'); }); + + it('handles reentrant mounting in synchronous mode', () => { + var mounts = 0; + class Editor extends React.Component { + render() { + return
{this.props.text}
; + } + componentDidMount() { + mounts++; + // This should be called only once but we guard just in case. + if (!this.props.rendered) { + this.props.onChange({rendered: true}); + } + } + } + + var container = document.createElement('div'); + function render() { + ReactDOM.render( + { + props = {...props, ...newProps}; + render(); + }} + {...props} + />, + container + ); + } + + var props = {text: 'hello', rendered: false}; + render(); + props = {...props, text: 'goodbye'}; + render(); + expect(container.textContent).toBe('goodbye'); + expect(mounts).toBe(1); + }); });