将 React 门户渲染到另一个组件 DOM 是否安全?

Is it safe to render a react portal into another component DOM?

考虑以下示例:

class GridContainer extends React.Component {
  ...
  render (){
    return <div>
      <Pagination portalId="portal-id"></>
      <Grid ...>
    </div>
  }
}

class Grid extends React.Component {
  ...
  render (){
    return <div>
      <div id="portal-id"></>
      <table ...>
    </div>
  }
}

class Pagination extends React.Component {
  ...
  render (){
    return return ReactDOM.createPortal(<div>Paginator DOM...</div>, document.getElementById(this.props.portalId));
  }
}

在其他组件中呈现门户是否安全 DOM?我已经测试过它并且有效,但我不知道这是否可靠。 Portals 文档提到您可以在 DOM 节点中呈现门户,但与组件 DOM.

无关

为什么这不同(这里推测)?在更新门户父组件时,在协调过程中,diff 可能会发现不一致并删除门户节点。

根据我的测试,上述情况并没有发生,但我不知道我是否可以假设 React 可以处理它。那么问题来了:

将门户渲染到另一个组件是否安全DOM?

安全吗?当然可以,但它可能不会像您期望的那样工作。

首先,您可以完全将 dom 转储到 React 创建的 div 中。

我遇到过几个会质疑这一事实的 React 程序员,但 Reacts 设计期望并说明在必要时直接编辑 dom。如果他们不这样做,就不会有 componentDidUpdate 或 React refs.

This documentation on integration with other libraries 可能是最相关的。

这是独家新闻:

  • React 不会接触渲染的内部结构 div,假设它在渲染结束时始终为空。它只会:
    • 创建新元素,此处不相关,只要留空即可。
    • 更新最初由 React 创建的现有元素。
    • 删除最初由 react 创建的元素。

所以只需创建空的 div 并将其单独留在 render 中,React 就不会弄乱它。

难点在这里; React 不保证渲染的时间。

这意味着您不知道当 Pagination 呈现时该元素是否真的存在,从而导致查询失败并且门户不显示。 componentDidUpdate 之所以有效,是因为 React 特别地 运行 在 更新 dom 之后 它。但是渲染是 运行 before dom 被更新。因此,如果 Pagination 在与 Grid 相同的扫描中呈现,则 div 可能尚未安装。

现在臭名昭著的堆栈溢出就是不要做那个答案:

只是不要那样做。 portal 的目的是让你在 React 容器之外渲染,同时让你的组件保持在 Reacts 渲染树中。如果你无论如何都在 React 渲染树中渲染,为什么不直接在那里渲染组件呢? (如果该陈述令人困惑,我怪你)

The Portals doc mention that you can render a portal in a DOM node but nothing about components DOM

这里没有提到,因为这是一般规则的特例; DOM 如果有更多惯用的方法,则不应在 React 中直接访问。

DOM 中发生大量内存泄漏。如果托管门户 (Grid) 的组件被重新渲染而门户组件 (Pagination) 未被渲染,这将导致分离 DOM,即内存泄漏。

门户组件呈现时附加门户的元素甚至可能不存在。