List列表组件在我们的项目中是最为常见的一种组件形式。你可以在比如刷微博抖音、购物车等等,这种列表状的场景很多很多。想象一下,如果带有大量视频或图片的应用中,当你滚动的时候,程序会不断的加载它们,这可能会对应用的性能产生影响。
因为性能是非常重要的一个方面,所以在渲染列表时,你需要确保它们是为最佳性能而设计的。
那么,在React中,你知道在渲染列表的时候,每个列表项都需要添加一个唯一的key。接下来让我们去了解React中的列表和Key,以及如何以正确的方式实现它。
写一个简单的List组件
renderList = (arr) => {
const list = arr.map((item) => <li>{item.name}</li> )
return (
<ul>{list}</ul>
)
}
render() {
const myList = [
{name: '李华'},
{name: '张飞'}
]
return (
<div>
{this.renderList(myList)}
<div/>
)
}
上面写了一个方法组件,传入一个list,页面输出以下内容:
- 李华
- 张飞
但是当你运行这段代码时,你会发现控制台React报出警告:
Warning: Each child in a list should have a unique "key" prop.
意思就是渲染list的每一个列表项没有加上唯一的key。
那么我们该如何在List组件中使用key
key呢其实就是提高React应用(组件)性能所必须的标识,它帮助React识别哪些项已更改(添加/删除/重新排序)。所以要为数组中的每个元素提供唯一标识,需要一个key。
为了更好地理解这一点,我们开始重构之前写的代码片段(包含key)。
renderList = (arr) => {
const list = arr.map((item) =>
<li key={u.id}>{item.name}</li>
)
return (
<ul>{list}</ul>
)
}
render() {
const myList = [
{id:'a',name: '李华'},
{id:'b',name: '张飞'}
]
return (
<div>
{this.renderList(myList)}
<div/>
)
}
在上面的代码片段中,你可以注意到我在每个li标签添加了key这个属性。还有数组中的每项都有一个与之关联的id,因此,每个li的key都被指定为数组中对应各项的id。这是为List中的列表项分配唯一key的最佳方法。
我可以只使用index作为key吗?(看情况)
为什么说看情况呢,请查看Robin Pokorny的这篇文章关于索引作为key是反模式的做法。 你可能一脸黑人问号 ,为什么我们不在循环数组时只使用索引作为key。 尽管许多开发者(包括我在内哈哈哈哈)在代码中都是这样做,但它并不一定是符合理想的。 React建议你不要使用索引作为key,因为它可能会对性能产生负面影响,并可能导致一些不稳定的组件行为。
const list = arr.map((item, index) =>
// 只有在item没有稳定id时才这样做
<li key={index}>
{item.name}
</li>
);
当索引作为key时,list的重新排序,或从list中添加和删除项可能会导致组件状态出现问题,重新排序项的索引会改变它,组件状态可能会混淆,而且会将旧key作用于不同的组件实例。
因此,我们要避免这种做法,并确保生成唯一的id指定为key。
在某些情况下,将索引指定为key是可以接受的。
哪些情况下使用索引作为key是可以接受的呢
- 如果您的列表是静态的,不会更改的。
- 该列表不会被过滤(从列表中添加/删除项目)。
- list数据中的item没有id。
如果所有这些情况都符合,那么你可以使用索引作为key。
注意:使用索引作为键可能会导致组件中出现潜在的意外行为
key必须是唯一的,但只是在其兄弟组件之间
请记住,尽管每个项的key都必须是唯一的,但此规则仅适用于数组。 换句话说,数组中的每个项目都需要具有唯一key,但它不必是全局唯一的。 可以在不相关的其他几个组件和列表中使用相同的key。
key是不会自动作为prop传递给组件的
在下面的示例中你可以看到我传递了item.id给key和id属性给MyComponent组件, 但是MyComponent不会把key作为属性通过props进行传递。如果你想使用key进行某些计算,那么你需要将它作为另一个属性传递。
const content = items.map((item) =>
<MyComponent
key={item.id}
id={item.id} />
)
在这个例子中,MyComponent可以读取props.id但不能读取props.key。
最后的结论
回顾一下今天的重点:
- 列表性能消耗很繁重,需要谨慎使用。
- 确保列表中的每个项目都有唯一的key。
- 除非您确定列表是静态列表(没有添加/重新排序/删除列表),否则优先不使用索引作为key。
- 切勿使用像Math.random()这样的不稳定方法来生成key。
- 如果使用不稳定的key,React将遇到性能下降和意外行为。