@samitouri / QOS-React / commits / 1fecba9230

Fix crash unmounting an empty Portal (#14820)

* Adds failing test for https://github.com/facebook/react/issues/14811 * Fix removeChild() crash when removing an empty Portal

Dan Abramov committed Feb 11, 2019 at 18:37 UTC 1fecba92307041e181ce425082d4d21ec8928728
2 files changed +39 -5
packages/react-dom/src/__tests__/ReactDOMFiber-test.js
+34
@@ -461,6 +461,40 @@ describe('ReactDOMFiber', () => {
461 expect(container.innerHTML).toBe('<div></div>');
462 });
463
464 + it('should unmount empty portal component wherever it appears', () => {
465 + const portalContainer = document.createElement('div');
466 +
467 + class Wrapper extends React.Component {
468 + constructor(props) {
469 + super(props);
470 + this.state = {
471 + show: true,
472 + };
473 + }
474 + render() {
475 + return (
476 + <div>
477 + {this.state.show && (
478 + <React.Fragment>
479 + {ReactDOM.createPortal(null, portalContainer)}
480 + <div>child</div>
481 + </React.Fragment>
482 + )}
483 + <div>parent</div>
484 + </div>
485 + );
486 + }
487 + }
488 +
489 + const instance = ReactDOM.render(<Wrapper />, container);
490 + expect(container.innerHTML).toBe(
491 + '<div><div>child</div><div>parent</div></div>',
492 + );
493 + instance.setState({show: false});
494 + expect(instance.state.show).toBe(false);
495 + expect(container.innerHTML).toBe('<div><div>parent</div></div>');
496 + });
497 +
498 it('should keep track of namespace across portals (simple)', () => {
499 assertNamespacesMatch(
500 <svg {...expectSVG}>
packages/react-reconciler/src/ReactFiberCommitWork.js
+5 -5
@@ -1038,12 +1038,12 @@ function unmountHostComponents(current): void {
1038 }
1039 // Don't visit children because we already visited them.
1040 } else if (node.tag === HostPortal) {
1041 - // When we go into a portal, it becomes the parent to remove from.
1042 - // We will reassign it back when we pop the portal on the way up.
1043 - currentParent = node.stateNode.containerInfo;
1044 - currentParentIsContainer = true;
1045 - // Visit children because portals might contain host components.
1041 if (node.child !== null) {
1042 + // When we go into a portal, it becomes the parent to remove from.
1043 + // We will reassign it back when we pop the portal on the way up.
1044 + currentParent = node.stateNode.containerInfo;
1045 + currentParentIsContainer = true;
1046 + // Visit children because portals might contain host components.
1047 node.child.return = node;
1048 node = node.child;
1049 continue;