Cổng cung cấp cách tốt nhất để kết xuất nút con thành nút DOM tồn tại bên ngoài hệ thống phân cấp DOM của thành phần gốc
ReactDOM.createPortal[child, container]
Đối số đầu tiên [child
] là bất kỳ , chẳng hạn như một phần tử, chuỗi hoặc đoạn. Đối số thứ hai [container
] là một phần tử DOM
Cách sử dụng
Thông thường, khi bạn trả về một phần tử từ phương thức kết xuất của một thành phần, phần tử đó sẽ được gắn vào DOM với tư cách là phần tử con của nút cha gần nhất
render[] {
// React mounts a new div and renders the children into it
return [
{this.props.children}
];
}
Tuy nhiên, đôi khi sẽ hữu ích khi chèn một phần tử con vào một vị trí khác trong DOM
render[] {
// React does *not* create a new div. It renders the children into `domNode`.
// `domNode` is any valid DOM node, regardless of its location in the DOM.
return ReactDOM.createPortal[
this.props.children,
domNode ];
}
Một trường hợp sử dụng điển hình cho các cổng thông tin là khi một thành phần gốc có kiểu overflow: hidden
hoặc z-index
, nhưng bạn cần thành phần con “phá vỡ” vùng chứa của nó một cách trực quan. Ví dụ: hộp thoại, thẻ di chuột và chú giải công cụ
Ghi chú
Khi làm việc với các cổng, hãy nhớ rằng điều đó trở nên rất quan trọng
Đối với các hộp thoại theo phương thức, hãy đảm bảo rằng mọi người đều có thể tương tác với chúng bằng cách tuân theo Thực tiễn tác giả theo phương thức WAI-ARIA
Dùng thử trên CodePen
Sự kiện bong bóng qua cổng
Mặc dù một cổng thông tin có thể ở bất kỳ đâu trong cây DOM, nhưng nó hoạt động giống như một React con bình thường theo mọi cách khác. Các tính năng như ngữ cảnh hoạt động giống hệt nhau bất kể cổng con có phải là cổng hay không, vì cổng vẫn tồn tại trong cây React bất kể vị trí trong cây DOM
Điều này bao gồm bong bóng sự kiện. Một sự kiện được kích hoạt từ bên trong một cổng thông tin sẽ lan truyền đến các phần tử tổ tiên trong cây React chứa, ngay cả khi các phần tử đó không phải là tổ tiên trong cây DOM. Giả sử cấu trúc HTML sau
Một thành phần
render[] {
// React mounts a new div and renders the children into it
return [
{this.props.children}
];
}
0 trong render[] {
// React mounts a new div and renders the children into it
return [
{this.props.children}
];
}
1 sẽ có thể bắt một sự kiện sủi bọt, chưa được bắt từ nút anh chị em render[] {
// React mounts a new div and renders the children into it
return [
{this.props.children}
];
}
2// These two containers are siblings in the DOM
const appRoot = document.getElementById['app-root'];
const modalRoot = document.getElementById['modal-root'];
class Modal extends React.Component {
constructor[props] {
super[props];
this.el = document.createElement['div'];
}
componentDidMount[] {
// The portal element is inserted in the DOM tree after
// the Modal's children are mounted, meaning that children
// will be mounted on a detached DOM node. If a child
// component requires to be attached to the DOM tree
// immediately when mounted, for example to measure a
// DOM node, or uses 'autoFocus' in a descendant, add
// state to Modal and only render the children when Modal
// is inserted in the DOM tree.
modalRoot.appendChild[this.el];
}
componentWillUnmount[] {
modalRoot.removeChild[this.el];
}
render[] {
return ReactDOM.createPortal[ this.props.children, this.el ]; }
}
class Parent extends React.Component {
constructor[props] {
super[props];
this.state = {clicks: 0};
this.handleClick = this.handleClick.bind[this];
}
handleClick[] { // This will fire when the button in Child is clicked, // updating Parent's state, even though button // is not direct descendant in the DOM. this.setState[state => [{ clicks: state.clicks + 1 }]]; }
render[] {
return [
Number of clicks: {this.state.clicks}
Open up the browser DevTools
to observe that the button
is not a child of the div
with the onClick handler.
];
}
}
function Child[] {
// The click event on this button will bubble up to parent, // because there is no 'onClick' attribute defined return [
Click
];
}
const root = ReactDOM.createRoot[appRoot];
root.render[];
Dùng thử trên CodePen
Nắm bắt một sự kiện nổi lên từ một cổng thông tin trong thành phần chính cho phép phát triển các bản tóm tắt linh hoạt hơn vốn không phụ thuộc vào cổng thông tin. Ví dụ: nếu bạn kết xuất một thành phần
render[] {
// React mounts a new div and renders the children into it
return [
{this.props.children}
];
}
3, thành phần gốc có thể nắm bắt các sự kiện của thành phần đó bất kể thành phần đó có được triển khai bằng cổng hay không