0%

react-ant-design-component-table-3

什么是唯一标识?

相信大家在使用React时,都曾遇到过下面这个警告信息吧:

1
Warning: Each child in a list should have a unique "key" prop.

这个警告信息的意思是:在渲染列表数据时,列表中每个元素都应该具有唯一的key属性。这个key属性是React用来识别每个子元素的唯一标识。React使用这个唯一标识来高效地更新和渲染组件。

这种警告经常发生在渲染多个相同元素时,比如使用js中的map进行循环渲染,下面的代码就是一个典型的例子,我们使用一个数组保存了四个按钮,然后使用map进行循环渲染这些按钮。

1
2
3
4
5
6
7
8
9
10
11
12
const actions = ['View', 'New', 'Edit', 'Delete'];
return (
<>
{
actions.map((action) => (
<Button type="primary">
{action}
</Button>
))
}
</>
)

由于我们没有为Button组件指定唯一标识,所以上面的代码会发出警告信息。我们可以为每个按钮添加一个唯一的key属性来解决这个问题。

1
2
3
4
5
actions.map((action) => (
<Button key={action} type="primary">
{action}
</Button>
))

因为这四个按钮的名字都不相同,属于唯一标识,我们可以用它来做Button的key属性。这样就可以消除警告信息了。

Table组件中的唯一标识

Ant Design中的Table组件也是列表数据,当然也需要唯一标识,Table组件中最重要的两个属性,dataSourcecolumns,都需要指定唯一标识。

为Columns指定唯一标识

在之前的文章中,我们定义Columns时,已经为每一列都指定了key属性。由下面的代码可知,key属性和dataIndex属性的值是相同的,因为dataIndex属性基本就是数据库中的表字段,可以确保唯一性,所以使用这个值作为key属性的值是一个不错的选择。

1
2
3
4
5
6
7
8
9
10
11
12
13
const columns = [
{
title: 'ID',
dataIndex: 'id',
key: 'id', // 唯一标识
},
{
title: '姓名',
dataIndex: 'name',
key: 'name', // 唯一标识
},
// ...
];

为dataSource指定唯一标识

columns不同,dataSource有两种方式来指定唯一标识:

  • dataSource中的每一行数据中添加一个唯一的key属性。
  • <Table>组件中指定rowKey属性。

第一种方式不是很常用,因为数据都是后端API返回的,我们无法要求后端API返回的数据中每一行都添加一个key属性。所以实际开发中,经常使用第二种。

1
2
3
4
5
6
<Table
loading={loading}
dataSource={tableData}
columns={columns}
rowKey="id">
</Table>

注意,这里的id不是随便取的名字,要求返回的列表数据中每一项都要有id属性(一般来说,后端返回的列表数据都会有id属性,因为在数据库层面,也需要id来区分不同的记录),也可以是其他属性,比如name, email等,只要确保它是唯一的就可以。

如果你的数据源中没有唯一标识,那么你可以自定义一个函数来生成唯一标识。

1
2
3
4
5
6
<Table
loading={loading}
dataSource={tableData}
columns={columns}
rowKey={(record) => generateUniqueKey(record)}>
</Table>

这里的generateUniqueKey是一个自定义函数,用于生成唯一标识。这个函数接收每一行数据(record)作为参数,返回一个字符串类型的唯一标识。我们可以使用多列组合的方式返回唯一标识,比如使用nameemail的组合。

1
2
3
function generateUniqueKey(record) {
return `${record.name}-${record.email}`; // 根据实际情况生成唯一标识
}

也可以使用第三方库来生成唯一标识,比如nanoid

1
2
3
// 使用nanoid生成唯一key
import { nanoid } from 'nanoid';
rowKey={() => nanoid()}

注意事项

需要注意的是:不能使用数组下标作rowKey,因为在数据发生变化时,数组下标会发生变化,导致React无法正确识别哪些数据发生了变化,从而引发渲染问题。

1
rowKey={(record, index) => index} // 不要使用数组元素下标做rowKey

总结

React要求列表数据中每个元素都要有一个唯标识(默认是key属性),其底层原因是为了Diff算法能够高效地比较和更新组件。Ant Design的Table组件也遵循了这个原则,我们可以通过如下几种方式来指定每一行数据的唯一标识。

React通过对比新旧虚拟DOM树的key值,快速识别增删改的组件。若未提供key或使用不稳定的key(如数组下标),会导致不必要的重新渲染甚至状态丢失。

为dataSource指定唯一标识

  1. dataSource中的每一行数据中添加一个唯一的key属性。
  2. 在Table组件中指定rowKey属性,可以是一个字符串(表示数据源中每一行数据的唯一标识)或者一个返回字符串的函数(用于生成每一行数据的唯一标识)。

为columns指定唯一标识

对于columns来说,必须在定义时指定一个唯一的key属性,因为Table组件的rowKey只作用于dataSource,而不作用于columns

今天下午的飞机回大连,上次回去还是端午节,转眼一个半月过去了,How time flies!