ReactJS - Portals
Portals 为组件提供了一种将其子组件渲染到其自身 DOM 层次结构之外的 DOM 节点中的方法。Portal 可用于模型对话框、弹出窗口、工具提示等,其中父组件(渲染组件)和子 DOM 节点(模型对话框)最好在不同的 DOM 节点中渲染。
让我们在本章中了解门户的工作原理以及如何在我们的应用程序中应用它。
门户的概念和用法
让我们假设主文档中有两个 DOM 节点,如下所示 −
<div id='root'></div> <div id='modalRoot'></div>
此处,根 DOM 节点将与主 React 组件连接。React 应用程序需要显示模态对话框时,将使用 modalRoot,方法是将模态对话框附加到 modelRoot DOM 节点中,而不是在其自己的 DOM 元素内渲染模型对话框。
这将有助于将模态对话框与实际应用程序分开。将模态对话框与其父 DOM 元素分离将使其免受其父 DOM 元素样式的影响。样式可以单独应用,因为模态对话框、工具提示等在样式方面与其父元素不同。
React 在 ReactDOM 包中提供了一种特殊的方法 createPortal 来创建门户。方法签名如下 −
ReactDOM.createPortal(child, container)
这里,
child 是父组件渲染的模型对话框、工具提示等。
render() { return ReactDOM.createPortal( this.props.children, // 模态对话框/工具提示 domNode // 组件外部的 dom ); }
container 是父 DOM 节点(上例中的 domNode)之外的 DOM 元素
应用门户
让我们创建一个新的 React 应用程序来学习如何在本节中应用门户。
首先,创建一个新的 React 应用程序并使用以下命令启动它。
create-react-app myapp cd myapp npm start
接下来,打开 App.css (src/App.css) 并删除所有 CSS 类并包含模态对话框的 CSS。
.modal { position: absolute; top: 0; bottom: 0; left: 0; right: 0; display: grid; justify-content: center; align-items: center; background-color: rgba(0,0,0,0.2); } .modalContent { padding: 20px; background-color: #fff; border-radius: 2px; display: inline-block; min-height: 300px; margin: 1rem; position: relative; min-width: 300px; box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); justify-self: center; }
接下来,打开 index.html (public/index.html) 并添加一个 DOM 节点来支持门户
<!DOCTYPE html> <html lang="en"> <head> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div style="padding: 10px;"> <div id="root"></div> </div> <div id="modalRoot"></div> </body> </html>
接下来,创建一个简单的组件 SimplePortal (src/Components/SimplePortal.js) 并渲染一个模态对话框,如下所示 −
import React from "react"; import PortalReactDOM from 'react-dom' const modalRoot = document.getElementById('modalRoot') class SimplePortal extends React.Component { constructor(props) { super(props); } render() { return PortalReactDOM.createPortal( <div className="modal" onClick={this.props.onClose} > <div className="modalContent"> {this.props.children} <hr /> <button onClick={this.props.onClose}>Close</button> </div> </div>, modalRoot, ) } } export default SimplePortal;
此处,
createPortal 创建新门户并呈现模态对话框。
模态对话框的内容通过 this.props.children
从组件的子项中检索。
关闭按钮操作通过 props 处理,并将由父组件处理。
接下来,打开 App 组件 (src/App.js),并使用 SimplePortal 组件,如下所示 −
import './App.css' import React from 'react'; import SimplePortal from './Components/SimplePortal' class App extends React.Component { constructor(props) { super(props); this.state = { modal: false } } handleOpenModal = () => this.setState({ modal: true }) handleCloseModal = () => this.setState({ modal: false }) render() { return ( <div className="container"> <div style={{ padding: "10px" }}> <div> <div><p>Main App</p></div> <div> <button onClick={this.handleOpenModal}> Show Modal </button> { this.state.modal ? ( <SimplePortal onClose={this.handleCloseModal}> Hi, I am the modal dialog created using portal. </SimplePortal> ) : null} </div> </div> </div> </div> ); } } export default App;
这里,
导入SimplePortal组件
添加了一个按钮来打开模态对话框
创建了一个处理程序来打开模态对话框
创建了一个处理程序来关闭模态对话框,并通过onClose props将其传递给SimplePortal组件。
最后,在浏览器中打开应用程序并检查最终结果。

总结
React portal 提供了一种在组件外部访问和处理 DOM 的简便方法。它使事件在不同的 DOM 节点之间冒泡,而无需任何额外的努力。