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
- 目錄結構
image-20201012134405623
通過 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
image-20201012134554207