在React中获取关键道具警告,即使设置了关键

ffx*_*sam 27 javascript reactjs

问题

我收到这个警告:

警告:数组或迭代器中的每个子节点都应该具有唯一的"键"支柱.检查EventsTable的render方法.有关更多信息,请参见fb.me/react-warning-keys.

react-runtime-dev.js?8fefd85d334323f8baa58410bac59b2a7f426ea7:21998警告:数组或迭代器中的每个子节点都应该有一个唯一的"key"prop.检查Event的render方法.有关更多信息,请参见fb.me/react-warning-keys.

资源

这是EventsTable:

EventsTable = React.createClass({
  displayName: 'EventsTable',

  render() {
    console.dir(this.props.list);

    return (
      <table className="events-table">
        <thead>
          <tr>
            {_.keys(this.props.list[0]).map(function (key) {
              if (key !== 'attributes') {
                return <th>{key}</th>;
              }
            })}
         </tr>
        </thead>

        <tbody>
          {this.props.list.map(function (row) {
            return (
              <Event key={row.WhatId} data={row} />
            );
          })}
        </tbody>
      </table>
    )
  }
});
Run Code Online (Sandbox Code Playgroud)

这是Event:

Event = React.createClass({
  displayName: 'Event',

  render() {
    return (
      <tr>
        {_.keys(this.props.data).map((x) => {
          if (x !== 'attributes')
            return <td>{this.props.data[x]}</td>;
        })}
      </tr>
    )
  }
});
Run Code Online (Sandbox Code Playgroud)

显然,我已经获得了key<Event />组件的道具.我遵循你应该包含key在组件上的约定,而不是HTML本身(换句话说,Event组件中的HTML标签).根据官方的React文档:

密钥应始终直接提供给数组中的组件,而不是数组中每个组件的容器HTML子代:

我非常困惑.为什么我会收到警告?

sma*_*sma 28

您是否尝试过加入key<th>标签?

         <tr>
            {_.keys(this.props.list[0]).map(function (key) {
              if (key !== 'attributes') {
                return <th key={key}>{key}</th>;
              }
            })}
         </tr>
Run Code Online (Sandbox Code Playgroud)

  • 但是,React文档是否说*不*将'key`放在HTML标记上?见[here](http://facebook.github.io/react/docs/multiple-components.html#dynamic-children) (4认同)

hlc*_*lcs 12

检查您传递给的变量是否key已定义,因为如果是undefined,则错误将是相同的,但看起来代码应该可以工作。


Mic*_*son 11

我意识到这个线程已经很老了,但我只是遇到了这个问题,这让我发疯了。当我意识到时我最终解决了它,因为我有一个<React.Fragment>也需要一个唯一键。

  • 我也想补充一下。我有一个: &lt;&gt;&lt;/&gt; 而不是 React.Fragment。我添加了 &lt;&gt;&lt;/&gt; 替换为 &lt;React.Fragment key={yourKeyHere}&gt;&lt;/React.Fragment&gt; ,现在一切正常,没有警告。 (2认同)

tot*_*dli 10

TL;博士

每次渲染列表(使用map)时,都会key向列表元素添加唯一属性(从map回调中返回的最顶层或"根"元素):

render() {
  return (
    <div>
      {this.props.data.map( element => {
         // Place the key on to the returned "root" element.
         // Also, in real life this should be a separate component...
         return <div key={element.id}>
           <span>Id (Name): </span>
           <span>{element.id} </span>
           <span>({element.name})</span>
         </div>;
      })}
    </div>
  )
}
Run Code Online (Sandbox Code Playgroud)

说明

了解React中的键

官方列表和密钥文档显示了如何使用列表,链接的对帐文档告诉了为什么.

基本上,当React重新呈现一个组件时,它会运行一个diff算法,找出新列表和之前版本之间发生了什么变化.比较并不总是微不足道,但如果每个元素中都有一个唯一的键,则可以清楚地识别出已发生变化的内容.请参阅doc中示例:

<!-- previous -->
<ul>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

<!-- new -->    
<ul>
  <li key="2014">Connecticut</li>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>
Run Code Online (Sandbox Code Playgroud)

很明显,添加了一个带键的新元素2014,因为我们拥有所有其他键并且没有更改.没有钥匙,这将是模糊的.

选择合适的钥匙

从现在开始很容易看出:

  • 为什么密钥应该是唯一的,但仅限于列表中的兄弟之间,因为比较只发生在给定列表的前一个元素和新元素中.
  • 对于前一版本和新版本之间的相同元素,键应保持相同,否则我们将比较不同的元素,并且无法跟踪更改.这就是为什么建议使用资源的id或(如果它没有)一些其他元素独有的数据,以及为什么你不应该使用像Math.random().

key在组件上放置属性

您应该将key属性放置到组件的约定更好的做法,因为当您迭代列表并想要呈现元素时,这清楚地表明您应该将该代码组织到单独的组件中.

key在循环中设置属性

您从文档中引用的声明:

密钥应始终直接提供给数组中的组件,而不是数组中每个组件的容器HTML子代:

意味着如果在循环中渲染组件,那么您应该在循环中设置key组件的属性,就像在EventsTable组件中一样:

{this.props.list.map(function (row) {
  return (
    <Event key={row.WhatId} data={row} />
  );
})}
Run Code Online (Sandbox Code Playgroud)

错误的方法是将其传递给它自己设置的组件key:

Event = React.createClass({
  displayName: 'Event',
  render() {
    // Don't do this!
    return (
      <tr key={this.props.data.WhatId}>
        {_.keys(this.props.data).map((x) => {
Run Code Online (Sandbox Code Playgroud)

没有此另一个很好的例子,在这篇文章中.