React 的 Portal 通过 React 的 context 和事件冒泡的机制工作。
在理解这个问题之前,首先要了解一些基本知识:
-
React Context:React 使用 context 来存储组件树的一些信息,比如事件处理程序。当组件使用 Portal 时,Portal 在 React 内部仍然保持在父组件树中,即使在 DOM 上渲染到其他地方。也就是说,Portal 的 context 依然从其父组件继承而来。
-
DOM 事件冒泡:DOM 中的事件(例如点击事件)通常会从触发事件的元素开始,然后逐步向上冒泡到父元素,直到 document 元素。在这个过程中,事件会按照 DOM 树的层级一层层地向上传递。
-
React 的事件代理:React 使用事件代理模式将所有事件都代理到顶层(
document
或者root
DOM 节点)进行处理。这意味着当在子组件中触发一个事件时,无论子组件是否使用了 Portal,React 都会将事件传递到其父组件,然后逐级往上冒泡,直到到达代理事件的顶层。
在 React 中,当一个子组件使用 Portal 将其内容渲染到其他 DOM 节点时,尽管在 DOM 结构上子组件不再是父组件的直接子节点,但在 React 的组件树中,子组件仍然是父组件的子节点。这意味着 React 在监听和处理事件时,会沿着组件树的路径(而不是 DOM 树的路径)冒泡事件。因此,子组件中触发的事件仍然会冒泡到父组件。
总结:Portal 在 DOM 结构上将子组件渲染到其他位置,但在 React 的组件树中,它仍然是父组件的子组件。这使得事件可以从子组件沿着组件树冒泡到父组件。