如何在同一个树中呈现子组件

时间:2016-04-19 13:14:35

标签: javascript reactjs render children

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

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

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

问题是,我做错了吗?这是唯一的方法,还是可以在旧的React树中创建新的React树,让React做出自己的魔力并自动更新?

非常感谢您提前

2 个答案:

答案 0 :(得分:0)

只要可能,您应该避免__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>
  );
}

我没有测试这段代码,它可能无法正常工作,但我希望你能得到这个想法并为你的问题扩展它

答案 1 :(得分:0)

根据您的描述,您的DOM树看起来像有多个所有者/编辑者:

  • <body>
    • ...其他HTML元素 - &gt;不是由反应管理
    • <DaliBox /> - &gt;由反应管理
      • ...其他HTML - &gt;不是由反应管理
      • <div id='pluginplaceholder'> - &gt;不是由反应管理,而是用新的(递归的)反应<DaliBox>替换
        • ...诸如此类

这不是理想的反应(温和地说)。感觉就像是在尝试对DOM结构中的随机级别应用反应 这是jQuery允许和促进的东西,但是反应并不顺利。

以最好的方式应用反应:

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

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

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