Portals 传送门

让组件"跳出"父容器渲染

先说结论:Portal 让你的组件可以渲染到 DOM 树的任意位置,但依然保留 React 树中的父子关系。

什么场景用到它?

  1. 模态框 (Modal) — 需要盖住全屏,不受父级的 overflow: hidden 限制
  2. Tooltip / Popover — 悬浮卡片
  3. Toast 通知 — 弹窗提示

这些场景都需要"视觉上跳出当前容器"。

怎么用?

import ReactDOM from "react-dom";

function Modal({ children }) {
  return ReactDOM.createPortal(
    children,
    document.body, // 渲染到 body 下
  );
}

第一个参数是 JSX,第二个是目标 DOM 节点。

事件冒泡(容易理解错)

这是最坑的点:虽然渲染到了 body 下,但在 React 树里还是原来的父子关系。

// DOM 结构:Body -> Modal
// React 树:App -> Container -> Modal

function App() {
  return (
    <Container>
      <Modal onClick={() => console.log("modal click")}>
        <div>我是模态框</div>
      </Modal>
    </Container>
  );
}

在 Modal 里点击,Container 的 onClick 也会触发!

因为 React 的合成事件是按 React 树走的,不是按 DOM 树。

总结

特点说明
渲染位置可以是任意 DOM 节点
React 关系保持不变
事件冒泡按 React 树走

记住:Portal 就是"视觉上跑出去了,但 React 关系还在"。