Skip to content

Portal example can cause issues if children access the DOM on componentDidMountΒ #272

Closed
@darrenscerri

Description

@darrenscerri

In the Portal example, the portal container is mounted in the DOM in the Modal's componentDidMount method

componentDidMount() {
  modalRoot.appendChild(this.el);
}

This means that when the portal is being mounted, children are initially mounted on a detached node and their componentDidMount is called when the component's node is not yet inserted in the DOM. Therefore, any DOM method that requires nodes to be mounted (getting node dimensions, focusing an element, etc.) and props like autoFocus will not work.

class Child extends React.Component {
  componentDidMount() {
    setTimeout(() => {
      let node = ReactDOM.findDOMNode(this);

      console.log(node.clientWidth);
      // 1980

      console.log(document.body.contains(node));
      // true
    }, 0);

    let node = ReactDOM.findDOMNode(this);

    console.log(node.clientWidth);
    // 0

    console.log(document.body.contains(node));
    // false
  }
  // The click event on this button will bubble up to parent,
  // because there is no 'onClick' attribute defined
  render() {
    return (
      <div className="modal">
        {/* Input will not focus */}
        <input autoFocus />
        <button>Click</button>
      </div>
    );
  }
}

This can be fixed by either moving Modal's appendChild method to componentWillMount or using the pattern used by https://github.com/tajo/react-portal/blob/master/src/Portal.js:

class Modal extends React.Component {
  componentWillUnmount() {
    if (this.el) {
      modalRoot.removeChild(this.el);
    }
  }

  render() {
    if (!this.el) {
      this.el = document.createElement("div");
      modalRoot.appendChild(this.el);
    }
    return ReactDOM.createPortal(this.props.children, this.el);
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions