具體可見: https://juejin.im/post/6844904133430870024
在react中,如果要渲染一個列表,我們會用map()函數將數組循環處理然后渲染到DOM,在處理循環時,“key” 是一個你需要包含的特殊字符串屬性。
很多時候,我們會使用當前列表的索引為key,但這樣做真的好嗎?
要討論這個問題,我們要從react的原理說起,我們react的執行步驟一般是:用state和jsx模板生成虛擬DOM,然后用虛擬DOM生成真實的 DOM,當我們state發生變化時,render函數執行,生成新的 虛擬DOM,然后比較新舊虛擬DOM的區別,找到區別,然后直接操作DOM,改變有區別的內容,這樣比傳統的操作DOM,極大的提升了性能。
再說虛擬DOM,虛擬DOM其實就是一個JS對象(['div',{class:'app'},'item']),虛擬DOM核心之一是diff算法,diff算法的核心之一是同層對比,如圖:

如果在第一層div時就有出現區別,那么對比結束,直接更新真實DOM中對應的當前節點,以此類推。。。
再說說key,假設我們在state中有一個列表[a,b,c],在遍歷渲染時用索引作為key,那么就是這樣:
a 0 b 1 c 2
如果我們執行一個操作,點擊刪除數組中的a, 我們的列表就是[b,c],在遍歷渲染時仍然會用索引作為key,結果如下:
b 0 c 1

如圖 ,我們如果不用索引為key , 程序能快速的對比出差異,反之也能對出差異,但是必須對比整個虛擬DOM,
這樣,程序仍然能正常執行,只不過大大消耗了新舊虛擬DOM的對比的性能,並可能導致組件狀態問題。
再舉一個vue的例子:為什么不能用index作為key?
舉個栗子:
<template> <div v-for="(item, index) in list" :key="index" >{{item.name}}</div> </template>
const list = [ { id: 1, name: "Person1" }, { id: 2, name: "Person2" }, { id: 3, name: "Person3" }, { id:4, name:"Person4" } ];
此時,刪除 “Person4” 是正常的,但是如果我刪除 “Person2” 就會出現問題。
刪除前
刪除后
這個時候,除了 Person1 之外,剩下的 Person3、Person4,因為被發現與相應 key
的綁定關系有變化,所以被重新渲染,這會影響性能。
如果此時 list
的 item
是 select 的選項,其中 Person3 是選中的,這個時候 Person2 被刪除了,用 index 作為 key 就會變成是 Person4 選中的了,這就產生了bug。
如果使用唯一id作為key,刪除 Person2 后,剩下的元素因為與 key
的關系沒有發生變化,都不會被重新渲染,從而達到提升性能的目的。此時,list
的 item
作為 select 的選項,也不會出現上面所描述的bug。