使

使用 React Portals 将组件传输到任何地方

2025-06-07

使用 React Portals 将组件传输到任何地方

在 React 中创建组件时,它们通常位于组件树中。这在大多数情况下是可以的,但有时我们希望组件的某些部分出现在组件树之外,或者完全不同的地方。当我们创建模态弹出窗口时,这是一个常见的需求,它们需要位于所有其他组件之上。我们可能在一个组件内创建这些窗口,但最终我们希望它们位于所有其他组件之上,而将它们嵌套在多个组件中可能会导致问题,因为它们z-index会位于它们所在的组件之下:

React 组件图

为了解决这个问题,我们可以使用 将模态框从其自身的组件中传送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;



Enter fullscreen mode Exit fullscreen mode

在 中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;
}


Enter fullscreen mode Exit fullscreen mode

创建我们的门户

创建 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;


Enter fullscreen mode Exit fullscreen mode

尽管我们将 DOM 元素传送到了modal-container,但它的行为仍然像普通的 React 子元素一样。由于 Portal 仍然存在于 React 树中,因此元素所在的上下文等功能仍然有效。

还要注意的是,虽然我们modal-containerModal同一个文件中,但 DOM 元素的传送目标位置可以是React 代码中的任何位置。因此,你可以将其传送到 DOM 中任何位置完全不同的子组件、元素或父级。它非常强大且实用——所以请明智地使用它。

让我们回顾一下我们的App.jsHTML:



    <!-- .... -->
    <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>


Enter fullscreen mode Exit fullscreen mode

现在,即使Modal位于我们的标题中,它也会在#modal-container我们使用按钮打开模式时出现:
Portal 在 React 中的工作原理

结论

Portal 是 React 中一个非常强大的工具。它能够有效解决基于组件的系统的主要问题——将某些元素传输到其他元素之上。因此,我希望您喜欢这篇 React Portal 指南。如果您正在学习 React,我建议您先掌握 JavaScript——您可以参考我的完整JavaScript 手册

祝你有美好的一天。

文章来源:https://dev.to/smpnjn/transporting-your-components-anywhere-with-react-portals-6li
PREV
仅使用 CSS 重建 Windows 98
NEXT
Javascript 浅拷贝 - 什么是浅拷贝?