使用antd
自带的table
组件时,遇到了控制台报错,虽然是warning
不影响使用,但红红的一块看起来总觉得不舒服,遂决定彻底解决这个问题:
通过控制台提示我们可以看到,问题出在“table
的数据缺失key
值”上。
首先,我们来明确下什么是key值:key
值是react
用来识别组件/元素的身份标识符
在react
中,每个组件/元素都拥有特定的key
,相同key
值的会被识别为同一个组件/元素,引起控制台报错。如下例所示:
this.state = {
statusList: [
{
value:"all",
title:"全部",
key:"all",
},{
value:"0",
title:"是",
key:"0",
},{
value:"1",
title:"否",
key:"1",
},{
value:"1",
title:"错误示例",
key:"1",
}
],
}
render () {
return(
<div>
<h3>状态栏</h3>
{this.state.statusList.map(
item => <div key={item.key}> {item.title} </div>)}
</div>
)
}
在这个案例中,后两个数组元素的key相同,执行代码后果不其然报了错:
其实,react是强制要求我们用key的,但是为什么这里只报了warning而不是error呢?是因为react默认为我们取数组的index作为key。
通常情况下,只要不涉及数组的新增、删除和排序等操作,那么使用index作为key值展示数据是没有问题的,但是一旦涉及到数组的动态变更,就很容易出现问题,比如:
class App extends React.Component{
constructor(props) {
super(props)
this.state = {
list: [{id: 1,title: 'a'}, {id: 2, title: 'b'}, {id: 3, title: 'c'}]
}
}
click() {
this.state.list.reverse()
}
render() {
return (
<ul>
<div onClick={this.click.bind(this)}>reverse</div>
{
this.state.list.map(function(item, index) {
return (
<li key={index}>{item.title} <input type="text"/></li>
)
}.bind(this))
}
</ul>
)
}
}
结果出现下面这种情况(图源网络):
点击reverse之后:
这是为什么呢?
原因在于:
- 点击reverse后,组件重新渲染得到新的虚拟dom
- 此时react会根据自己的diff算法对新老两个虚拟dom进行比较
- 发现key值相同后,react便会判定组件没有发生变更,
componentWillReceiveProps
方法不会被执行 - 接着,react会检查key相同的组件的文本内容,发现有变化之后更改了这部分
- 最后,react会检查组件包含的input组件,由于input组件没有发生变化,又与父组件传入的props没有关系,所以input组件也不变,就导致了这种bug的出现
因此,在选择组件的key属性时必须是唯一且稳定的,使用random随机函数生成也不好,因为数组动态改变时会导致数组元素中的每项都重新销毁然后重新创建,有一定的性能开销;另外也可能导致一些意想不到的问题出现
最好的办法是,如果数据中有指定的id值,那么就使用数据中的id属性作为唯一key值,如果没有,可以指定一个全局变量来添加稳定唯一的key值。
class Test extends React.Component {
this.keyCounter = 1;
//给数组data赋上新属性key值
addKey(data) {
data.map((item,index)=>{
data[index]['key'] = this.keyCounter++;
})
return data;
}
}
而在react中,Table的dataSource和columns里的数据值都需要指定 key 值。对于 dataSource 默认将每列数据的 key 属性作为唯一的标识。
好,既然原理都清楚了,那我们就回到题目上来——antd table表格的key值缺失该如何解决呢?
我列下报错的几种情况,大家按照自己的实际运行效果进行处理:
1. 设置了rowKey属性,但所指定字段的值不是唯一的:
Warning: Each child in an array or iterator should have a unique "key" prop.
2. 没有设置rowKey属性,不过设置了table的columns属性的配置中第一列的key(react所需),但key所指定字段的值不是唯一的:
Warning: Each record in table should have a unique
keyprop,or set
rowKeyto an unique primary key.
3.没有设置rowKey属性,也没有设置columns属性的配置中第一列的key(react所需)
Warning: Each record in dataSource of table should have a unique
keyprop, or set
rowKeyto an unique primary key,see [https://u.ant.design/table-row-key](https://u.ant.design/table-row-key)
此时可以通过给每一行(dataSource)和每一列(columns)设置特定的key值来解决:
let columns = [{
key: '1',
title: '人民币',
dataIndex: 'title'
},{
key: '2',
title: '美元',
dataIndex: 'title'
},{
key: '3',
title: '日元',
dataIndex: 'title'
},{
key: '4',
title: '英镑',
dataIndex: 'title'
}]
let dataSource = [{
key: 1,
title: 'aaaa'
},{
key: 2,
title: 'bbbb'
},{
key: 3,
title: 'cccc'
}]
<Table
columns={columns}
dataSource={dataSource}
/>
也可以通过上面描述的全局变量设定key值来解决!
还可以为表格添加rowKey,当然了,也必须是稳定唯一的值:
<Table
rowKey={(record, index) => `complete${record.id}${index}`}
...
/>