无法为react.js组件

时间:2016-02-18 15:34:57

标签: javascript reactjs react-jsx

再一次,看起来最微不足道的任务让我的项目陷入停顿。这是我的情况:

我在ASP.NET 4.5 MVC 6 SPA中使用react.js。我的设计使得我有三个主要区域用于反应:顶级菜单,侧面菜单和主要内容区域。由于不同区域的时间和装载要求,我有3个独立的反应组件层次结构,每个主要部分一个。也许这就是问题的一部分,但在某个地方我认为这是允许的。

所以,在某一点上,我从Web服务中提取顶级菜单节点列表,并将它们绑定到顶层菜单反应组件,然后对侧面菜单执行相同操作。当有人点击其中一个菜单项时,它会将新数据加载到内容面板区域,这些是我加载到div中的反应组件。

在我加载新组件之前,所有内容都按预期工作,直到我尝试在内容面板中卸载组件。当我呼叫ReactDOM.unmountComponentAtNode()传递我的div时,我得到以下内容:

Uncaught Error: Invariant Violation: ReactMount: Two valid but unequal nodes with the same的数据reactid : .0(…)

我现在有几个疑虑:

  • 首先我不明白为什么它似乎在DOM的任何地方寻找反应节点,当我传入一个我想要卸载的特定元素时。在DOM元素的范围内,我指定只有一个反应组件;我希望这就足够了。
  • 其次,我在顶级反应组件上设置特定键的许多尝试都失败了。我阅读并理解您在创建组件时从组件外部设置键的建议/规则,而不是直接在内部元素上设置键,因此我的组件创建为:

    ReactDom.render(<ManageCommunitiesContainer brandData={mcmData} key="manageComms" />, $("#reactRoot")[0]);

我已经为我正在使用的三个顶级组件中的每一个添加了唯一键,但是当我在chrome的开发者工具的react插件中检查它们时,所有3具有相同的data-reactid,这只是&#39; .0&#39;。

我已经在内部设置了来自内部的子对象的键,在没有问题的情况下做出反应。但是在我通过javascript添加的顶级组件上我没有做任何事情导致它们具有有意义的运行时值...一个人必须做什么才能为根组件分配唯一键,从而能够在以后卸载它们?因为我无法安装它们,它们会堆积在内存中。

感谢。

2 个答案:

答案 0 :(得分:0)

React键与data-reactid不同。了解React组件与DOM Elements不同。有一个很好的React blog article可以解释组件,实例和元素之间的区别。

我会说尝试手动卸载组件并渲染全新的树木正在艰难地做事。 React的优势在于您只需执行初始渲染,然后操纵状态以使React更新DOM元素。

我的第一个建议是尝试回到单个组件层次结构。可以在根组件的状态中捕获时序要求。像这样:

class TopMenu extends React.Component {
  render() {
    const data = this.props.data;

    if (!data) {
      return <div>Loading...</div>;
    }

    // render your menu with the data provided...
    return <div>{data}</div>;
  }
}

class SideMenu...
class Content...

class Page extends React.Component {
  constructor(...args) {
    super(...args);
    this.state = {
      topMenuData: undefined,
      sideMenuData: undefined,
      contentData: undefined
  }

  componentDidMount() {
    // call ready callback provided via props with this instance
    // so someone outside can update our state when data loads
    this.props.ready(this);
  }

  render() {
    return (
      <div>
        <TopMenu data={this.state.topMenuData} />
        <SideMenu data={this.state.sideMenuData} />
        <Content data={this.state.contentData} />
      </div>);
  }
}


// main js code
function pageMounted(page) {
  // register callbacks with your code that is loading data from
  // the server.
  topMenuLoader.then(data => page.setState({ topMenuData: data }));
  sideMenuLoader.then(data => page.setState({ sideMenuData: data }));
  contentLoader.then(data => page.setState({ contentData: data }));
}

React.render(<Page ready={pageMounted} />, rootElement);

使用这种样式,最终你可以将加载逻辑移动到React组件层次结构本身的某个地方,并摆脱那个允许外部世界更新状态的ready回调。

即使由于您的约束而无法创建单个组件层次结构,您也可以使用该ready回调的相同基本思想创建3个您永远不会销毁的顶级React层次结构,而只是提供新数据无论何时需要更改渲染内容,都可以通过setState

答案 1 :(得分:0)

过了几天后的午夜回答:似乎与我总是使用html包装标签的相同元素id有关。

我认为明智地总是将包含反应内容的元素指定为具有相同的id,因此我可以通过编程方式找到它,然后卸载组件,然后展开{{1}内容,以便准备好持有一个新的标记,无论是否作出反应。

最终我看到我前一段时间做过的一些测试都使用了独特的元素ID,并按计划进行了工作,所以我现在已经改变了很多,认为这是有影响力的。和以往一样,我并不是100%清楚为什么我的方法导致它窒息,看起来像是从我坐的地方采取的一套合法的行动,但是......你有它。

希望它能帮到某个人。