React 使用组件密钥来确定集合中的哪些组件需要重新渲染,而不是每次发生任何变化时仅重新渲染整个组件集合。
钥匙是强制性的
假设我们有以下代码,它通过一个数组循环并创建一系列列表项目组件:
1const reptiles = ['alligator', 'crocodile', 'snake'];
2
3const reptileComponents = reptiles.map((reptile) => {
4 <li>
5 {reptile}
6 </li>
7});
8
9const container = document.createElement('div');
10document.body.appendChild(container);
11ReactROM.render(<ul>{reptileComponents}</ul>, container);
这将导致 React 向控制台投放警告,提示在一个数组或迭代器中的每个孩子都应该有一个独特的密钥。
事實上,今天至少一切都會正常,因為生產包通常會忽略這些類型的警告,所以你需要確保在開發過程中注意到它們。
仅仅因为React今天正确地渲染了无钥匙的组件,并不意味着React在未来将正确地渲染无钥匙的组件。
要修复上述代码,您只需要在列表项目中包含一个钥匙
属性:
1const reptiles = ['alligator', 'crocodile', 'snake'];
2
3const reptileComponents = reptiles.map((reptile) => {
4 <li key={reptile}>
5 {reptile}
6 </li>
7});
8
9const container = document.createElement('div');
10document.body.appendChild(container);
11ReactROM.render(<ul>{reptileComponents</ul>, container);
钥匙必须是独一无二的,但只在兄弟之间
密钥有助于确保只有已更改的组件才能重新渲染,唯一可以跟踪实际更改的组件的方法就是用一个独特的密钥标记它们。
幸运的是,密钥的独特性仅适用于集合本身,密钥不需要在您的整个React应用程序中独特,只需要在您的集合中的兄弟姐妹中独特。
如果我们要运行以下代码,加上另一个鱼,我们就会发出警告:
1const reptiles = ['alligator', 'crocodile', 'snake', 'alligator'];
2
3const reptileComponents = reptiles.map((reptile) => {
4 <li key={reptile}>
5 {reptile}
6 </li>
7});
8
9const container = document.createElement('div');
10document.body.appendChild(container);
11ReactROM.render(<ul>{reptileComponents}</ul>, container);
类似于关于缺少密钥的警告实际上不会引起任何问题,今天有重复密钥仍然正确地渲染,在内部,缺乏独特的密钥可能会导致额外的重复渲染,这可能会使我们的应用减慢。
该警告还提到,事情可能会在未来发生变化,并且YMMV作为非独特的密钥可能会导致重复和/或遗漏的组件。
要解决这个重复的密钥问题,一个快速的解决方案是将数组的索引作为密钥而不是值:
1const reptiles = ['alligator', 'crocodile', 'snake', 'alligator'];
2
3const reptileComponents = reptiles.map((reptile) => {
4 <li key={index}>
5 {reptile}
6 </li>
7});
8
9const container = document.createElement('div');
10document.body.appendChild(container);
11ReactROM.render(<ul>{reptileComponents</ul>, container);
它足以在固定顺序数组中拼凑,但如果数组项目的顺序在未来可能会发生变化,则不是最理想的解决方案。
在这些场景中,最好使用某种内部唯一标识符(ID)。