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

IT技术 javascript reactjs
2021-05-14 15:10:53

问题

我收到此警告:

警告:数组或迭代器中的每个孩子都应该有一个唯一的“键”props。检查 EventsTable 的渲染方法。有关更多信息,请参阅fb.me/react-warning-keys

react-runtime-dev.js?8fefd85d334323f8baa58410bac59b2a7f426ea7:21998 警告:数组或迭代器中的每个孩子都应该有一个唯一的“key”props。检查事件的渲染方法。有关更多信息,请参阅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>
    )
  }
});

这是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>
    )
  }
});

问题

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

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

我很困惑。为什么我会收到警告?

4个回答

您是否尝试key<th>标签中添加一个

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

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

解释

理解 React 中的键

官方Lists and Keys文档显示了您应该如何使用列表,链接的对帐文档说明了原因。

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

<!-- 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>

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

选择合适的键

从现在开始很容易看出:

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

key在组件上放置属性

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

key在循环中设置属性

您从文档中引用的声明:

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

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

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

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

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

在本文中有另一个很好的例子

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

我也遇到了这个问题,并在以下链接后修复了它

喜欢:

{_data.map(function(object, i){
     return <div className={"row"} key={i}> 
           {[ object.name ,
      <b className="fosfo" key={i}> {object.city} </b> , // remove the key
          object.age
      ]}
</div>; 
})}