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

数组中的每个子元素都应该有一个唯一的“key”道具。 检查TableComponent的渲染方法。

我的TableComponent渲染方法返回:

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

TableHeader组件是单行,也有一个唯一的键赋给它。

行中的每一行都是由一个具有唯一键的组件构建的:

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

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


当前回答

在ReactJS中,如果你要渲染一个元素数组,那么每个元素都应该有一个唯一的键。通常这种情况会产生一个列表。

例子:

function List() {
  const numbers = [0,1,2,3];
 
  return (
    <ul>{numbers.map((n) => <li> {n} </li>)}</ul>
  );
}

 ReactDOM.render(
  <List />,
  document.getElementById('root')
);

在上面的例子中,它使用li标签创建了一个动态列表,所以由于li标签没有唯一键,所以它显示了一个错误。

固定后:

function List() {
  const numbers = [0,1,2,3];
 
  return (
    <ul>{numbers.map((n) => <li key={n}> {n} </li>)}</ul>
  );
}

 ReactDOM.render(
  <List />,
  document.getElementById('root')
);

当你没有唯一键时使用map的替代解决方案(react eslint不推荐这样做):

function List() {
  const numbers = [0,1,2,3,4,4];
 
  return (
    <ul>{numbers.map((n,i) => <li key={i}> {n} </li>)}</ul>
  );
}

 ReactDOM.render(
  <List />,
  document.getElementById('root')
);

实例:https://codepen.io/spmsupun/pen/wvWdGwG

其他回答

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

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

在代码中,每个<TableRowItem key={项。id} data={item} columns={columnNames}/>试图在其中呈现一些没有键的子元素。

请看这个例子。

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

在本例中,如果我们没有给<b>元素一个键,并且我们只想更新对象。在city中,React需要重新渲染整个行,而不仅仅是元素。

代码如下:

const data = [
  { name: "Nuri", age: 28, city: "HO" },
  { name: "Talib", age: 82, city: "HN" },
  { name: "Jenny", age: 41, city: "IT" },
];

const ExampleComponent = React.createClass({
  render: function () {
    const infoData = this.props.info;
    return (
      <div>
        {infoData.map((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(<ExampleComponent info={data} />, document.body);

下面由@Chris发布的答案比这个答案更详细。

React文档中关于按键在协调中的重要性:按键

只需将唯一键添加到组件

data.map((marker)=>{
    return(
        <YourComponents 
            key={data.id}     // <----- unique key
        />
    );
})

这是一个简单的例子,我使用了一个react条件&&先映射,在我已经添加了用户id键,以确保它是唯一的

 <tbody>
                                    {users &&
                                    users.map((user) => {
                                        return <tr key={user._id}>
                                            <td>{user.username}</td>
                                            <td><input
                                                name="isGoing"
                                                type="checkbox"
                                                checked={user.isEnabled}
                                                onChange={handleInputChangeNew}/></td>
                                            <td>{user.role.roleTitle} - {user.role.department.departmentName}</td>
                                            {/*<td className="text-right">
                                                    <Button>
                                                        ACTION
                                                    </Button>
                                                </td>*/}
                                        </tr>
                                    })
                                    }


                                    </tbody>

下面是React文档,它们很好地解释了Key属性的使用,Key应该在父组件中定义,不应该在子组件中使用。反应文档

我认为在处理表(或类似的例子)时,为了重用性,应该将创建的唯一键从父组件传递给子组件。

因为如果你正在创建一个表,这意味着你正在从父表传递数据。如果你赋值key={row.name},可能当前数据有name属性,但如果你想在其他地方使用这个表组件,你假设在你传递的每一行数据中,你都有name属性。

由于工程师将在父组件中准备数据,因此工程师应该基于这些数据创建一个键函数。

const keyFunc = (student) => {
    return student.id;
  }; 

在这种情况下,工程师知道它正在发送什么数据,它知道每一行都有唯一的id属性。也许在不同的数据集中,数据集是股票价格它没有id属性,只有符号

 const keyFunc = (stock) => {
        return stock.symbol;
      }; 

这个keyFunc应该作为道具传递给子组件,以保证可重用性和唯一性。