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

How to render child component in the same tree

本文关键字:组件 一棵树      更新时间:2023-09-26

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

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

我所做的是,在ComponentDidMount内部,在DOMNode中找到<plugin />标记,然后使用ReactDOM.render来渲染传入必要道具的PluginPlaceholder。问题是,当为Chrome使用React DevTools扩展时,我可以看到这会创建某种不同的"树",迫使我手动更新。

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

提前非常感谢

您应该尽可能长时间地避免__dangerouslySetInnerHTML。对于你的情况(如果我说得对的话),你不需要。

让我们考虑<DaliBox />和标记<div><p><PluginPlaceholder /></p></div>。从您的问题中,我了解到您具有以某种方式解析此标记的功能。让我们考虑函数parseMarkup,它返回类似的东西

[
  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-->未由react管理
      • <div id='pluginplaceholder'>-->不由react管理,但将用新的(递归)react <DaliBox>替换
        • 。。。等等

这对于react来说并不理想(委婉地说)。感觉就像是在尝试对DOM结构中的随机级别应用react
这是jQuery允许并促进的,但它与react不太配合。

按最佳到最差的方式应用反应:

  • 应用react的理想方法是让react完全垄断您的DOM结构的一部分,包括所有子体。然后您有一个react实例,管理DOM/HTML的特定(如果不是全部的话)
  • 不太理想,但仍然是常见的做法:应用程序对DOM结构的多个不相关部分作出反应。通过具有多个反应实例(多个ReactDOM.render()
  • 甚至不太理想,但如果绝对不可避免的话,可能是可以接受的:让react完全垄断DOM结构的1个(或多个)部分,但忽略最低级别。通过将CCD_ 12应用于这些最低水平
  • 灾难的配方,要不惜一切代价避免:让react管理树中的DOM级别1-4,但不是级别5和6,另一个react实例管理DOM级别7及更低

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

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