Portals
Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。
ReactDOM.createPortal(child, container)
第一个参数(child
)是任何可渲染的 React 子元素,例如一个元素,字符串或 fragment。
第二个参数(container
)是一个 DOM 元素。
应用场景: 对话框、悬浮卡以及提示框:
实列
实现一个modal
import React, { PureComponent } from 'react'
import { createPortal } from 'react-dom'
class Modal extends PureComponent {
constructor(props) {
super(props)
const doc = window.document
console.log('window.document', window.document)
this.node = doc.createElement('div')
doc.body.appendChild(this.node)
}
componentWillUnmount() {
window.document.body.removeChild(this.node)
}
render() {
// React 并*没有*创建一个新的 div。它只是把子元素渲染到 `domNode` 中。
// `domNode` 是一个可以在任何位置的有效 DOM 节点。
return createPortal(
<div className="mask">
<div className="modal">
<h3>Modal</h3>
{this.props.children}
</div>
</div>,
this.node
)
}
}
export default Modal
- 目录结构

通过 Portal 进行事件冒泡
尽管 portal 可以被放置在 DOM 树中的任何地方,但在任何其他方面,其行为和普通的 React 子节点行为一致。由于 portal 仍存在于 React 树, 且与 DOM 树 中的位置无关,那么无论其子节点是否是 portal,像 context 这样的功能特性都是不变的。
这包含事件冒泡。一个从 portal 内部触发的事件会一直冒泡至包含 React 树的祖先,即便这些元素并不是 DOM 树 中的祖先。假设存在如下 HTML 结构:
import React, { PureComponent } from 'react'
import Modal from '../../components/Modal'
class MyModal extends PureComponent {
state = {
count: 0,
}
handleClick = () => {
this.setState({
count: this.state.count + 1,
})
}
render() {
return (
<div
onClick={this.handleClick}
style={{
height: '100%',
}}
>
我是测试
<p>点击次数{this.state.count}</p>
<Modal>
<div>我是Modal</div>
</Modal>
</div>
)
}
}
export default MyModal

网友评论