Closed
Description
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
Labels
No labels