简体   繁体   English

无法为react.js组件设置密钥

[英]Unable to set the key for react.js components

Once again, what seems like the most trivial of tasks has brought my project to a halt. 似乎最琐碎的任务再次使我的项目停顿了。 Here is my situation: 这是我的情况:

I'm using react.js inside an ASP.NET 4.5 MVC 6 SPA. 我在ASP.NET 4.5 MVC 6 SPA中使用react.js。 I have designed such that I have three main areas where I use react: a top menu, a side menu and a main content area. 我的设计使我在三个主要区域使用了react:顶部菜单,侧面菜单和主要内容区域。 Because of the timing and loading requirements of the different areas, i have 3 separate react component hierarchies, one for each major section. 由于不同区域的时间和负载要求,我有3个独立的React组件层次结构,每个主要部分一个。 Perhaps that is part of the issue right there, but somewhere i got the idea that this is allowable. 也许那是那里问题的一部分,但是在某个地方,我想到了这是可以接受的。

So at a point, I pull a list of top menu nodes from a web service, and bind them to a top menu react component, then do the same for the side menu. 因此,在某一时刻,我从Web服务中提取了一个顶层菜单节点列表,并将它们绑定到顶层菜单react组件,然后对侧面菜单执行相同的操作。 When someone clicks on one of the menu items, it loads new data into the content panel area, and these are react components which i load into a div. 当有人单击菜单项之一时,它将新数据加载到内容面板区域中,这些是我加载到div中的react组件。

Everything works as expected to a point, until i attempt to unload the component in the content panel, before i load a new one into it. 一切工作都按预期进行,直到我尝试在内容面板中卸载该组件,然后再向其中加载新组件。 When i call ReactDOM.unmountComponentAtNode() passing in my div I get the following: 当我通过我的div调用ReactDOM.unmountComponentAtNode() ,我得到以下信息:

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

I have a couple of qualms at this point: 在这一点上,我有一些疑虑:

  • first off i don't understand why it seems to be looking everywhere in the DOM for react nodes, when I've passed in a specific element i want unmounted. 首先,我不明白为什么在DOM中的各处似乎都需要有React节点,而当我传入一个我想卸载的特定元素时。 within the scope of the DOM element i've specified there's only one react component; 在我指定的DOM元素范围内,只有一个react组件; i would expect that to suffice. 我希望这样就足够了。
  • secondly, my many attempts to set specific keys on the top-level react components have failed. 其次,我多次尝试在顶级React组件上设置特定键均失败了。 I read and understand the advice/rule that you have to set the key from outside the component as you create it, and not directly on the elements from inside, so my components are created as: 我阅读并理解了建议/规则,您在创建键时必须在组件外部设置键,而不是直接在内部从元素上设置键,因此我的组件创建为:

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

i've added unique keys to each of the three top-level components i'm using, and yet when i inspect them in the react plug-in for chrome's developer tools, all 3 have the same data-reactid , which is simply '.0'. 我已经为正在使用的三个顶级组件中的每个组件添加了唯一键,但是当我在chrome开发人员工具的react插件中检查它们时,所有这三个组件都具有相同的data-reactid ,即“ 0.0' 。

I have set keys on child objects from inside react within loops with no issues. 我已经从内部在子对象上设置了子对象的键,在循环内没有任何问题。 But on my top-level components added via javascript nothing i do results in them having meaningful run-time values...what does a person have to do to assign unique keys to root components, and thus be able to un-mount them later? 但是在通过javascript添加的顶级组件上,我什么也没做,导致它们具有有意义的运行时值...一个人必须做什么才能为根组件分配唯一的键,从而能够在以后卸载它们? because i can't un-mount them, they're piling up in memory. 因为我无法卸载它们,所以它们堆积在内存中。

thanks. 谢谢。

React keys aren't the same as the data-reactid . React键与data-reactid Understand that React Components are not the same as DOM Elements. 了解React组件与DOM元素不同。 There's a good React blog article that explains the difference between Components, Instances and Elements. 有一篇不错的React博客文章 ,解释了Components,Instances和Elements之间的区别。

I'll say that trying to manually unmount components and render completely new trees is doing things the hard way. 我要说的是,尝试手动卸载组件并渲染全新的树很难。 React's strengths show when you just do an initial render and then manipulate your state to cause React to update the DOM elements. 当您仅执行初始渲染然后处理状态以使React更新DOM元素时,React的优势就会显示出来。

My first suggestion is to try to get back to a single component hierarchy. 我的第一个建议是尝试回到单个组件层次结构。 The timing requirements can be captured in the state of the root component. 时序要求可以在根组件的状态下捕获。 Something like this: 像这样:

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);

With this style, eventually you might be able to move the loading logic to somewhere within the React component hiearchy itself and get rid of that ready callback which is letting the outside world update the state. 通过这种风格,最终您可能可以将加载逻辑移至React组件层次结构本身内的某个位置,并摆脱使外界更新状态的ready回调。

Even if you cannot create a single component hierarchy due to your constraints, you can use the same basic idea of that ready callback to create 3 top-level React hierarchies that you never destroy and instead just supply new data via setState whenever you need to change what is rendered. 即使由于约束而无法创建单个组件层次结构,也可以使用该ready回调的相同基本思想来创建3个您从未销毁的顶级React层次结构,而仅在需要更改setState通过setState提供新数据呈现什么。

Past midnight several days later answer: seems to have something to do with my always using the same element id for the html wrapping tag. 几天后的午夜过后,答案:似乎与我始终使用html包装标签相同的元素ID有关。

i thought it'd be smart to always specify the element which contained the react stuff as having the same id, so i could programmatically find it, then un-mount the component, then flat-out .clear() the contents so as to ready it to hold a new piece of mark-up, whether react or not. 我认为总是将包含反应.clear()的元素指定为具有相同的id是明智的,因此我可以以编程方式找到它,然后卸载组件,然后将.clear()内容平整以便准备好进行新的标记,无论是否做出反应。

eventually i saw that a few tests i had done a while ago were using unique element id's and had worked as planned, so i've changed enough of them now to believe this is impactful. 最终,我看到我前一段时间做的一些测试使用的是唯一元素id并按计划进行,因此我现在对它们进行了足够的更改,以至于相信这是有影响的。 as ever, it's not 100% clear to me why my approach caused it to choke, seems like a legitimate enough set of actions to take from where i sit, but...there you have it. 像以往一样,我还不是100%清楚为什么我的方法会导致它窒息,似乎可以从我坐着的地方采取足够的合法行动,但是...有。

hope it helps someone sometime. 希望它能在某个时候对某人有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM