使用 React Portals 将组件传输到任何地方
在 React 中创建组件时,它们通常位于组件树中。这在大多数情况下是可以的,但有时我们希望组件的某些部分出现在组件树之外,或者完全不同的地方。当我们创建模态弹出窗口时,这是一个常见的需求,它们需要位于所有其他组件之上。我们可能在一个组件内创建这些窗口,但最终我们希望它们位于所有其他组件之上,而将它们嵌套在多个组件中可能会导致问题,因为它们z-index
会位于它们所在的组件之下:
为了解决这个问题,我们可以使用 将模态框从其自身的组件中传送createPortal
到模板的另一部分。这样我们就可以将组件放置在任何我们想要的位置,例如 HTML 树的底部、body
标签内或其他元素内。即使元素存在于组件树中,createPortal
我们也可以将其放置在任何我们想要的位置。
使用 React Portals
为了向您展示门户的工作原理,请考虑在文件中包含以下基本的 React 代码App.js
。在这里,我们希望模态框显示在所有其他内容之上。因此,我们创建了一个div
名为 的#modal-container
。这是我们最终希望所有模态框都进入的地方:
import logo from './logo.svg';
import './App.css';
import { useState } from 'react'
import Modal from './components/Modal.js';
function App() {
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<button onClick={() => setIsModalOpen(!isModalOpen)}>
Click to Open Modal
</button>
<Modal modalState={isModalOpen} onClickEvent={() => setIsModalOpen(!isModalOpen)}>
This is Modal Content!
</Modal>
</header>
<div id="modal-container"></div>
</div>
);
}
export default App;
在 中App.js
,我导入了一个名为 的组件Modal
。这是我们的 Modal 组件,它会在用户点击按钮时弹出。每当isModalOpen
使用 设置为 true时setIsModalOpen()
,模态框就会出现。否则,它会消失。
我还使用了一些 CSS 来确保我们的模态框确实出现在其他所有内容之上:
#modal-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
z-index: 9999;
height: 100%;
pointer-events: none;
}
.modal {
position: absolute;
top: 200px;
background: white;
border-radius: 4px;
left: calc(50% - 100px);
width: 200px;
}
创建我们的门户
创建 Portal 非常简单 - 只需一个函数即可createPortal()
。与 React 中返回一些 DOM 元素不同,我们返回的Portal
是 。createPortal()
它接受两个参数 - 我们要返回的 DOM 元素(在本例中为模态框)以及我们要将 DOM 元素传送到的 DOM 元素。因此,我们的第二个参数是document.getElementById('modal-container')
,因为我们想将所有模态框放入#modal-container
:
import { createPortal } from 'react-dom';
function Modal({modalState, onClickEvent}) {
if(!modalState) return null;
return (
createPortal(
<div className="modal">
<button onClick={onClickEvent}>Close Modal</button>
<div className="modal-content">Modal Content goes here</div>
</div>,
document.getElementById('modal-container')
)
);
};
export default Modal;
尽管我们将 DOM 元素传送到了modal-container
,但它的行为仍然像普通的 React 子元素一样。由于 Portal 仍然存在于 React 树中,因此元素所在的上下文等功能仍然有效。
还要注意的是,虽然我们modal-container
在Modal
同一个文件中,但 DOM 元素的传送目标位置可以是React 代码中的任何位置。因此,你可以将其传送到 DOM 中任何位置完全不同的子组件、元素或父级。它非常强大且实用——所以请明智地使用它。
让我们回顾一下我们的App.js
HTML:
<!-- .... -->
<button onClick={() => setIsModalOpen(!isModalOpen)}>
Click to Open Modal
</button>
<Modal modalState={isModalOpen} onClickEvent={() => setIsModalOpen(!isModalOpen)}>
This is Modal Content!
</Modal>
</header>
<div id="modal-container"></div>
现在,即使Modal
位于我们的标题中,它也会在#modal-container
我们使用按钮打开模式时出现:
结论
Portal 是 React 中一个非常强大的工具。它能够有效解决基于组件的系统的主要问题——将某些元素传输到其他元素之上。因此,我希望您喜欢这篇 React Portal 指南。如果您正在学习 React,我建议您先掌握 JavaScript——您可以参考我的完整JavaScript 手册。
祝你有美好的一天。
文章来源:https://dev.to/smpnjn/transporting-your-components-anywhere-with-react-portals-6li