createPortal:把 React 子树挂到 DOM 别处去
知识背景
Modal、Tooltip、全局通知往往要求 DOM 节点挂在 body 末尾(避免父级 overflow: hidden、z-index 堆叠上下文问题)。createPortal(child, domNode) 让你在逻辑上仍是 React 树的一部分(context、事件冒泡仍可按规则工作),但真实 DOM 插入到指定容器。
知识详解与通俗解释
1. 基本用法
jsx
import { createPortal } from 'react-dom';
function Modal({ children }) {
const el = document.getElementById('modal-root');
return createPortal(children, el);
}需在 HTML 里预留 <div id="modal-root"></div>,或在挂载时用脚本创建。
2. 事件冒泡(面试常问)
Portal 出去的 DOM 在物理结构上不在父节点下,但 React 17+ 对事件系统做了调整:合成事件会按 React 树结构冒泡,而不是严格跟随原生 DOM 树。理解成本:仍以组件树为准思考业务,细节以官方版本说明为准。
3. 与纯 CSS position: fixed 对比
Portal 解决的是层级与裁剪问题;简单弹层若样式可控,不一定非要 Portal,但设计系统里 Modal 几乎标配 Portal。
4. 卸载与内存
组件卸载时,Portal 内容一并卸载。若在 document.body 上直接 appendChild 而不走 React,会造成泄漏,应统一走 Portal。
总结
- Portal = 逻辑在 React 树、DOM 在任意节点。
- 适合 Modal、Drawer、Toast、Dropdown溢出容器 等场景。
- 事件与可访问性(焦点陷阱、aria)需配合库或自研逻辑,Portal 只解决挂载位置。