寫 React / Vue 項目時爲什麼要在列表組件中寫 key,其作用是什麼?
-
沒有綁定key的情況下,並且在遍歷模板簡單的情況下,會導致虛擬新舊節點對比更快,節點也會複用。而這種複用就是就地複用,一種鴨子辨型的複用。
<div id="app">
<div v-for="i in dataList">{{ i }}</div>
</div>
var vm = new Vue({ el: '#app', data: { dataList: [1, 2, 3, 4, 5] } })
以上例子,v-for的內容會生成一下dom的節點數組,我們標記身份:
[
'<div>1</div>', // id: A
'<div>2</div>', // id: B
'<div>3</div>', // id: C
'<div>4</div>', // id: D
'<div>5</div>' // id: E
]
❝❝1.改變dataList數據,進行數據位置替換,對比改變後的數據
❞❞
vm.dataList = [4, 1, 3, 5, 2] // 數據位置替換
// 沒有key的情況, 節點位置不變,但是節點innerText內容更新了
[
'<div>4</div>', // id: A
'<div>1</div>', // id: B
'<div>3</div>', // id: C
'<div>5</div>', // id: D
'<div>2</div>' // id: E
]
// 有key的情況,dom節點位置進行了交換,但是內容沒有更新
// <div v-for="i in dataList" :key='i'>{{ i }}</div>
[
'<div>4</div>', // id: D
'<div>1</div>', // id: A
'<div>3</div>', // id: C
'<div>5</div>', // id: E
'<div>2</div>' // id: B
]
❝❝增刪dataList列表項
❞❞
vm.dataList = [3, 4, 5, 6, 7] // 數據進行增刪
// 1. 沒有key的情況, 節點位置不變,內容也更新了
[
'<div>3</div>', // id: A
'<div>4</div>', // id: B
'<div>5</div>', // id: C
'<div>6</div>', // id: D
'<div>7</div>' // id: E
]
// 2. 有key的情況, 節點刪除了 A, B 節點,新增了 F, G 節點
// <div v-for="i in dataList" :key='i'>{{ i }}</div>
[
'<div>3</div>', // id: C
'<div>4</div>', // id: D
'<div>5</div>', // id: E
'<div>6</div>', // id: F
'<div>7</div>' // id: G
]
從以上來看,不帶有key,並且使用簡單的模板,基於這個前提下,可以更有效的複用節點,diff速度來看也是不帶key更加快速的,因爲帶key在增刪節點上有耗時。這就是vue文檔所說的默認模式。但是這個並不是key作用,而是沒有key的情況下可以對節點就地複用,提高性能。
這種模式會帶來一些隱藏的副作用,比如可能不會產生過渡效果,或者在某些節點有綁定數據(表單)狀態,會出現狀態錯位。VUE文檔也說明了 「「這個默認的模式是高效的,但是隻適用於不依賴子組件狀態或臨時 DOM 狀態 (例如:表單輸入值) 的列表渲染輸出.」」
但是KEY的作用是什麼呢?
❝❝key是給每一個vnode的唯一id,可以依賴key,更準確,更快的拿到oldVnode中對應的vnode節點。
❞❞
-
更準確
因爲帶key就不是就地複用了,在sameNode函數
a.key === b.key
對比中可以避免就地複用的情況。所以會更準確。 -
更快
利用key的唯一性生成map對象來獲取對應的節點,比遍歷方式更快。
本文使用 mdnice 排版