提问者:小点点

了解React.js中数组子项的唯一键


我正在构建一个React组件,它接受一个JSON数据源并创建一个可排序表。
每个动态数据行都有一个唯一的键分配给它,但我仍然得到一个错误:

数组中的每个子项都应该有一个唯一的“键”道具。
检查TableComponent的render方法。

我的TableComponent呈现方法返回:

<table>
  <thead key="thead">
    <TableHeader columns={columnNames}/>
  </thead>
  <tbody key="tbody">
    { rows }
  </tbody>
</table>

tableheader组件是单行,并且还为其分配了唯一的键。

rows中的每个row都是由具有唯一键的组件生成的:

<TableRowItem key={item.id} data={item} columns={columnNames}/>

TableRoWitem如下所示:

var TableRowItem = React.createClass({
  render: function() {

    var td = function() {
        return this.props.columns.map(function(c) {
          return <td key={this.props.data[c]}>{this.props.data[c]}</td>;
        }, this);
      }.bind(this);

    return (
      <tr>{ td(this.props.item) }</tr>
    )
  }
});

是什么原因导致了唯一键道具错误?


共2个答案

匿名用户

您应该为每个子元素以及子元素中的每个元素添加一个键。

这样React就可以处理最小的DOM更改。

在您的代码中,每个都试图在没有键的情况下呈现它们内部的一些子项。

请查看此示例。

尝试从div的元素中删除key={i}(并检查控制台)。

在示例中,如果我们不给元素一个键,并且只想更新object.city,React需要重新呈现整行,而不是只呈现元素。

代码如下:

var data = [{name:'Jhon', age:28, city:'HO'},
            {name:'Onhj', age:82, city:'HN'},
            {name:'Nohj', age:41, city:'IT'}
           ];

var Hello = React.createClass({

    render: function() {

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

React.render(<Hello info={data} />, document.body);

@chris在下方贴出的答案比这个答案要详细得多。请查看https://stackoverflow.com/a/43892905/2325522

对核对中关键字的重要性做出反应:关键字

匿名用户

迭代数组时要小心!!

一个常见的误解是,使用数组中元素的索引是抑制您可能熟悉的错误的一种可接受的方法:

Each child in an array should have a unique "key" prop.

然而,很多情况下并非如此!这是反模式,在某些情况下会导致不想要的行为。

React使用key道具来理解组件到DOM元素的关系,然后将其用于协调过程。因此,关键字始终保持唯一是非常重要的,否则,React很有可能会混淆元素并变异出不正确的元素。同样重要的是,这些键在所有重新呈现过程中保持静态,以保持最佳性能。

话虽如此,但只要已知数组是完全静态的,就不一定需要应用上述内容。不过,只要有可能,就鼓励采用最佳做法。

一位React开发者在本期GitHub中表示:

  • 关键不是真正的性能,它更多的是身份(这反过来又会导致更好的性能)。随机分配和更改的值不是标识
  • 如果不知道您的数据是如何建模的,我们就无法实际地[自动]提供密钥。如果您没有ID
  • ,我建议使用某种散列函数
  • 我们在使用数组时已经有了内部键,但它们是数组中的索引。插入新元素时,这些键是错误的。

简而言之,应该是:

  • 唯一-密钥不能与同级组件的密钥相同。
  • 静态-键不应在呈现之间更改。

根据上面的解释,仔细研究以下示例,并尽可能地实现推荐的方法。

<tbody>
    {rows.map((row, i) => {
        return <ObjectRow key={i} />;
    })}
</tbody>

这可能是在React中迭代数组时最常见的错误。这种方法在技术上并不“错误”,只是...“危险”如果你不知道自己在做什么。如果您正在迭代一个静态数组,那么这是一个完全有效的方法(例如,导航菜单中的链接数组)。但是,如果您正在添加、删除、重新排序或筛选项目,那么您就需要小心了。看看官方文档中的这篇详解吧。

null

class MyApp extends React.Component {
  constructor() {
    super();
    this.state = {
      arr: ["Item 1"]
    }
  }
  
  click = () => {
    this.setState({
      arr: ['Item ' + (this.state.arr.length+1)].concat(this.state.arr),
    });
  }
  
  render() {
    return(
      <div>
        <button onClick={this.click}>Add</button>
        <ul>
          {this.state.arr.map(
            (item, i) => <Item key={i} text={"Item " + i}>{item + " "}</Item>
          )}
        </ul>
      </div>
    );
  }
}

const Item = (props) => {
  return (
    <li>
      <label>{props.children}</label>
      <input value={props.text} />
    </li>
  );
}

ReactDOM.render(<MyApp />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>