我正在构建一个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>
)
}
});
是什么导致唯一键道具错误?
根据React文档,每一行/项都应该有一个唯一的键。
键帮助React识别哪些项已经更改、添加或删除。
就我个人而言,我更喜欢使用加密接口来生成一个随机UUID:
(crypto在vanilla-js中是内置的)
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={crypto.randomUUID()}>item {number}
</li>
);
我认为在处理表(或类似的例子)时,为了重用性,应该将创建的唯一键从父组件传递给子组件。
因为如果你正在创建一个表,这意味着你正在从父表传递数据。如果你赋值key={row.name},可能当前数据有name属性,但如果你想在其他地方使用这个表组件,你假设在你传递的每一行数据中,你都有name属性。
由于工程师将在父组件中准备数据,因此工程师应该基于这些数据创建一个键函数。
const keyFunc = (student) => {
return student.id;
};
在这种情况下,工程师知道它正在发送什么数据,它知道每一行都有唯一的id属性。也许在不同的数据集中,数据集是股票价格它没有id属性,只有符号
const keyFunc = (stock) => {
return stock.symbol;
};
这个keyFunc应该作为道具传递给子组件,以保证可重用性和唯一性。
这可能对某些人有帮助,也可能没有,但它可能是一个快速的参考。这也类似于上面给出的所有答案。
我有很多使用下面结构生成列表的位置:
return (
{myList.map(item => (
<>
<div class="some class">
{item.someProperty}
....
</div>
</>
)}
)
经过一些尝试和错误(以及一些挫折)后,向最外层的块添加一个键属性解决了这个问题。另外,注意<>标记现在被<div>标记取代。
return (
{myList.map((item, index) => (
<div key={index}>
<div class="some class">
{item.someProperty}
....
</div>
</div>
)}
)
当然,在上面的例子中,我一直天真地使用迭代索引(index)来填充键值。理想情况下,您应该使用列表项唯一的内容。
我不做详细的解释,但这个答案的关键是“关键”
只需将key属性放在标签中,并确保每次迭代时都赋予它唯一的值
#确保键的值不与其他值冲突
例子
<div>
{conversation.map(item => (
<div key={item.id } id={item.id}>
</div>
))}
</div>
conversation是一个数组,如下所示:
const conversation = [{id:"unique"+0,label:"OPEN"},{id:"unique"+1,label:"RESOLVED"},{id:"unique"+2,label:"ARCHIVED"},
]