Portal 子组件的事件冒泡
React Portal 渲染到其他 DOM 节点后,事件如何冒泡到父组件
问题
子组件使用 Portal 渲染到其他 DOM 节点,点击事件能否冒泡到父组件?
解答
可以。Portal 虽然在 DOM 结构上渲染到其他位置,但在 React 组件树中仍然是父组件的子节点,事件会沿着组件树(而非 DOM 树)冒泡。
function Parent() {
const handleClick = () => {
console.log('父组件捕获到点击事件');
};
return (
<div onClick={handleClick}>
<h1>父组件</h1>
<PortalChild />
</div>
);
}
function PortalChild() {
return ReactDOM.createPortal(
<button>点击我</button>,
document.getElementById('portal-root')
);
}
在上面的例子中,点击按钮会触发父组件的 handleClick,即使按钮实际渲染在 #portal-root 节点下。
这是因为 React 使用事件代理机制,将所有事件代理到根节点统一处理。当事件触发时,React 会沿着组件树路径冒泡,而不是 DOM 树路径。Portal 组件在 React 组件树中的位置没有改变,所以事件冒泡行为也不会改变。
关键点
- Portal 改变的是 DOM 渲染位置,不改变 React 组件树结构
- React 事件沿着组件树冒泡,而非 DOM 树
- React 使用事件代理,在根节点统一处理事件
- Portal 的 context 仍然从父组件继承
目录