React Portals 简述及其用例

React Portals 简述及其用例
作者 | Madushika Perera
译者 | 王强
策划 | 李俊辰

React Portal 是一种优秀的方法,可以将子组件渲染到由组件树层次结构定义的父 DOM 层次结构之外的 DOM 节点中。Portal 的最常见用例是子组件需要从视觉上脱离父容器的情况,如下所示。

  • 模态对话框

  • 工具提示

  • 悬浮卡片

  • 加载器

可以使用 ReactDOM.createPortal(child, container) 创建一个 Portal。这里的 child 是一个 React 元素、片段或字符串,而 container 是 Portal 应该注入到的 DOM 位置(节点)。

以下是使用上述 API 创建的一个示例模态(modal)组件。
const Modal =({ message, isOpen, onClose, children })=> {
  if (!isOpen) return null
  return ReactDOM.createPortal(
    <div className="modal">
      <span className="message">{message}</span>
      <button onClick={onClose}>Close</button>
    </div>,
    domNode)
}

即使 Portal 是在父 DOM 元素外部渲染的,其行为也类似于应用程序中的常规 React 组件。它可以访问 props 和 context API。这是因为 Portal 位于 React Tree 层次结构内。想要看一看 React Portal 的实践示例,请查看在 Bit 的组件中心上分享的这个组件(你也可以使用 Bit 共享和重用组件):

https://bit.dev/semantic-org/semantic-ui-react/portal

React Portals 简述及其用例示例:使用 React Portal 的 React 组件——在 Bit.dev 上分享

我们为什么需要它?

当我们在特定元素(父组件)中使用模态时,模态的高度和宽度将从模态所在的组件继承。因此,模态可能会被裁剪,而无法在应用程序中正确显示。传统上模态需要 CSS 属性,如 overflow:hidden 和 z-index,以避免出现这一问题。

React Portals 简述及其用例被父组件覆盖高度和宽度的一个典型模态

上面的代码示例将导致在根下的嵌套组件内部渲染这个模态。使用浏览器检查这个应用程序时,它将显示元素,如下所示。

React Portals 简述及其用例没有 React Portal 的模态渲染

让我们看看如何在这里使用 React Portal。以下代码将使用 createPortal(),在 root 树层次结构之外创建一个 DOM 节点来解决这个问题。
const Modal =({ message, isOpen, onClose, children })=> {
  if (!isOpen) return null;
  return ReactDOM.createPortal(
     <div className="modal">
      <span>{message}</span>
      <button onClick={onClose}>Close</button>
     </div>
    ,document.body);
  }
function Component() {
  const [open, setOpen] = useState(false)
  return (
    <div className="component">
      <button onClick={() => setOpen(true)}>Open Modal</button>
      <Modal 
       message="Hello World!" 
       isOpen={open} 
       onClose={() =>
 setOpen(false)}
      />
    </div>
  )
}

下面显示的是一个 DOM 树层次结构,这是在使用 React Portal 时产生的,其中模态将被注入到 root 的外部,并与 root 处于同一级别。

React Portals 简述及其用例使用 React Portal 渲染的模态

由于这个模态是在根层次结构之外渲染的,因此其尺寸不会被父组件继承或更改。

React Portals 简述及其用例渲染为 Portal 的模型

你可以在这个 CodeSandbox 中找到这个示例,在其中可以试用代码、查看 Portal 的工作方式并解决所讨论的问题。

https://codesandbox.io/s/react-portals-l0sy5

使用 Portal 时要注意的事项

使用 React Portal 时,你应该注意几个问题。下面提到的这些行为并不是直观可见的,你需要了解它们才行,因此我想在这里提一下。

  • 事件冒泡(Event Bubbling)将照常工作:通过将事件传播到 React 树的祖先,事件冒泡将按预期工作,而与 DOM 中的 Portal 节点位置无关。

  • React 可以控制 Portal 节点及其生命周期:通过 Portal 渲染子元素时,React 仍然可以控制其生命周期。

  • Portal 仅影响 DOM 结构:Portal 仅影响 HTML DOM 结构,而不影响 React 组件树。

  • 预定义 HTML 挂载点:使用 Portal 时,你需要定义一个 HTML DOM 元素作为 Portal 组件的挂载点。

    小结    

当我们需要在正常的 DOM 层次结构之外渲染子组件,而又不通过 React 组件树层次结构破坏事件传播的默认行为时,React Portal 就会派上用场。当渲染诸如模态、工具提示、弹出消息之类的组件时,它会很有用。

你可以在 React 官方文档中找到有关 Portal 的更多信息:

https://reactjs.org/docs/portals.html

感谢阅读,欢迎在下面的评论中分享你的看法。

延伸阅读

https://blog.bitsrc.io/understanding-react-portals-ab79827732c7

React Portals 简述及其用例

发表评论

邮箱地址不会被公开。 必填项已用*标注

相关