使用v-for時爲什麼需要設置key值,並且不用index作爲key的原因

v-for中的key

使用v-for更新已渲染的元素列表時,默認用就地複用策略;列表數據修改的時候,他會根據key值去判斷某個值是否修改,如果修改,則重新渲染這一項,否則複用之前的元素;
我們在使用的使用經常會使用index(即數組的下標)來作爲key,但其實這是不推薦的一種使用方法;

舉個?

const list = [
    {
        id: 1,
        name: 'test1',
    },
    {
        id: 2,
        name: 'test2',
    },
    {
        id: 3,
        name: 'test3',
    },
]

<div v-for="(item, index) in list" :key="index" >{{item.name}}</div>

上面這種是我們做項目中常用到的一種場景,因爲不加key,vue現在直接報錯,所以我使用index作爲key;下面列舉兩種常見的數據更新情況

  1. 在最後一條數據後再加一條數據
const list = [
    {
        id: 1,
        name: 'test1',
    },
    {
        id: 2,
        name: 'test2',
    },
    {
        id: 3,
        name: 'test3',
    },
    {
        id: 4,
        name: '我是在最後添加的一條數據',
    },
]

此時前三條數據直接複用之前的,新渲染最後一條數據,此時用index作爲key,沒有任何問題;

  1. 在中間插入一條數據
const list = [
    {
        id: 1,
        name: 'test1',
    },
    {
        id: 4,
        name: '我是插隊的那條數據',
    }
    {
        id: 2,
        name: 'test2',
    },
    {
        id: 3,
        name: 'test3',
    },
]

此時更新渲染數據,通過index定義的key去進行前後數據的對比,發現

之前的數據 之後的數據


key: 0  index: 0 name: test1     key: 0  index: 0 name: test1
key: 1  index: 1 name: test2     key: 1  index: 1 name: 我是插隊的那條數據
key: 2  index: 2 name: test3     key: 2  index: 2 name: test2
                                 key: 3  index: 3 name: test3

通過上面清晰的對比,發現除了第一個數據可以複用之前的之外,另外三條數據都需要重新渲染;

是不是很驚奇,我明明只是插入了一條數據,怎麼三條數據都要重新渲染?而我想要的只是新增的那一條數據新渲染出來就行了

最好的辦法是使用數組中不會變化的那一項作爲key值,對應到項目中,即每條數據都有一個唯一的id,來標識這條數據的唯一性;使用id作爲key值,我們再來對比一下向中間插入一條數據,此時會怎麼去渲染

之前的數據 之後的數據

key: 1  id: 1 index: 0 name: test1     key: 1  id: 1 index: 0  name: test1
key: 2  id: 2 index: 1 name: test2     key: 4  id: 4 index: 1  name: 我是插隊的那條數據
key: 3  id: 3 index: 2 name: test3     key: 2  id: 2 index: 2  name: test2
                                       key: 3  id: 3 index: 3  name: test3

現在對比發現只有一條數據變化了,就是id爲4的那條數據,因此只要新渲染這一條數據就可以了,其他都是就複用之前的;

同理在react中使用map渲染列表時,也是必須加key,且推薦做法也是使用id,也是這個原因;

其實,真正的原因並不是vue和react怎麼怎麼,而是因爲Virtual DOM 使用Diff算法實現的原因,


下面大致從虛擬DOM的Diff算法實現的角度去解釋一下

vue和react的虛擬DOM的Diff算法大致相同,其核心是基於兩個簡單的假設:

  • 兩個相同的組件產生類似的DOM結構,不同的組件產生不同的DOM結構。
  • 同一層級的一組節點,他們可以通過唯一的id進行區分。基於以上這兩點假設,使得虛擬DOM的Diff算法的複雜度從O(n^3)降到了O(n)。

引用React’s diff algorithm中的例子:

diff1.jpg

當某一層有很多相同的節點時,也就是列表節點時,Diff算法的更新過程默認情況下也是遵循以上原則。
比如一下這個情況:
diff2.jpg

我們希望可以在B和C之間加一個F,Diff算法默認執行起來是這樣的:
diff3.jpg

即把C更新成F,D更新成C,E更新成D,最後再插入E,是不是很沒有效率?

所以我們需要使用key來給每個節點做一個唯一標識,Diff算法就可以正確的識別此節點,找到正確的位置區插入新的節點。
diff4.jpg

所以一句話,key的作用主要是爲了高效的更新虛擬DOM。另外vue中在使用相同標籤名元素的過渡切換時,也會使用到key屬性,其目的也是爲了讓vue可以區分它們,否則vue只會替換其內部屬性而不會觸發過渡效果。

參考

vue官方文檔
爲什麼使用v-for時必須添加唯一的key?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章