如何在同一棵树中渲染子组件

How to render child component in the same tree

这可能是我这边的误会,但我有以下情况:

我有一个名为 DaliBox 的 React 组件,它具有一些智能(拖动、调整大小等),可能包含一些我不知道的 HTML 并使用 __dangerouslySetInnerHTML 分配给 DaliBox。但是,如果在 HTML 中有一个自定义标签(在本例中为 <plugin />),那么我希望它托管一个新的 React 组件(PluginPlaceholder),它将充当 DaliBox 容器。

我所做的是,在 ComponentDidMount 内部,在 DOMNNode 中找到 <plugin /> 标签,然后使用 ReactDOM.render 渲染传递必要道具的 PluginPlaceholder。问题是,当使用 Chrome 的 React DevTools 扩展时,我可以看到这会产生某种不同的 "tree",迫使我手动更新内容。

问题是,我是不是做错了什么?这是唯一的方法还是可以在旧的 React 树中创建新的 React 树并让 React 发挥它的魔力并自动更新?

非常感谢您

您应该尽可能避免 __dangerouslySetInnerHTML。对于你的情况(如果我做对了)你不需要一个。

让我们考虑 <DaliBox /> 和标记 <div><p><PluginPlaceholder /></p></div>。根据您的问题,我了解到您具有以某种方式解析此标记的功能。因此,让我们考虑 parseMarkup 的函数 returns 类似于

[
  component: 'div',
  children: [
    component: 'p',
    children: [
      component: 'PluginPlaceholder'
    ]
  ]
]

不,你可以在没有任何魔法的情况下渲染你的树,比如:

renderChildren(markup) {
  let component;
  let children = [];
  // get component. PluginPlaceholder or just string like 'div' or 'p'
  switch (markup.component) {
    case 'PluginPlaceholder':
      component = PluginPlaceholder;
      break;
    default:
      component = markup.component;
  }
  // recursively render children
  if (markup.children) {
    children = this.renderChildren(markup.children);
  }
  return React.createElement(component, [], children);
}

render() {
  return (
    <DaliBox>
      {this.renderChildren(parseMarkup(this.props.markup))}
    </DaliBox>
  );
}

我没有测试这段代码,它可能不会工作,但我希望你能理解并扩展它来解决你的问题

根据您的描述,您的 DOM 树似乎有多个所有者/编辑者:

  • <body>
    • ... 其他 HTML 元素 --> 不受 react
    • 管理
    • <DaliBox /> --> 由 React 管理
      • ...其他 HTML --> 不受反应管理
      • <div id='pluginplaceholder'> --> 不由 React 管理,但要用新的(递归)React 替换 <DaliBox>
        • ...等等

这不是反应的理想选择(委婉地说)。感觉就像您正在尝试将反应应用于 DOM 结构中的随机级别。
这是 jQuery 允许和促进的事情,但它与 react 不相配。

按照从最好到最差的方式应用 React:

  • 应用 React 的理想方式是让 React 完全垄断 你的 DOM 结构的 1 部分,包括所有后代。然后你有一个反应实例,管理一个特定的(如果不是全部)你的 DOM/ HTML.
  • 不太理想,但仍然是常见的做法:将反应应用于 DOM 结构的多个不相关部分。通过有多个反应实例(多个 ReactDOM.render()s)。
  • 更不理想,但如果绝对不可避免,也许可以接受:让 React 完全垄断 DOM 结构的 1 个(或更多)部分,但忽略最低级别。通过将 _dangerouslySetInnerHTML() 应用到最低级别。
  • 灾难的秘诀,要不惜一切代价避免:让 React 管理 DOM 树中的 1-4 级,但不是 5 级和 6 级,以及另一个要管理的 React 实例 DOM 7 级及以下。

在你的递归情况下,我建议坚持理想情况:根本不使用 _dangerouslySetInnerHTML()。 或者重新考虑您的代码/行为/DOM 中适用 React 的特定部分。 (也许您不需要在 DOM 的 drag/drop 部分做出反应)。

这背后的原因:React 依赖于它自己的 DOM 的(隐藏的)虚拟副本,并且依赖虚拟副本和 DOM 始终保持同步。如果其他一些代码开始混淆 DOM-react 应该管理的部分,那么你的虚拟 DOM 和真实的 DOM 不再同步,你的 react 代码将很快产生不可预测的结果结果,并变得完全不可调试。