結論
在使用非文本節點的組件,且這個組件沒有依賴於響應式的props,此時使用index作為key,那么此時對於列表的刪除操作會導致視圖錯亂。
背景
在動態刪除v-for渲染的列表的過程中,如果key指定為index,則可能出現渲染錯亂的問題。比如,你的列表有兩行,你明明刪了第一行,結果卻是第二行消失了。
解析
問題源於key的重復,假設你的列表有兩行,當你刪了第一行,那么第二行的key就變成了第一行的key,這兩個key是相同的。基於VirtualDOM的庫會把key相同的組件認作同一個組件,因而不會去更新視圖。
也就是說,你刪了第一行,本來預期的第二行變成了第一行,結果變成因為key相同,最后第一行保持不變,反而是第二行消失了。
為什么我沒有復現
大部分時候我們即使使用index作為key,不會復現這個問題,這好像與我們上述分析不符。但是事實上,“使用index作為key並且不會出問題”這種場景,其實過程是這樣的:
-
第一步:通過修改數據刪除第一行,數據變化引起vue去更新視圖,更新的過程中發現key相同,最終第一行保持不變,反而是第二行消失。這是第一次render。
-
第二步:第一行的VirtualDOM的確沒有變,但是第一行的組件的props變了,由原來第一行的props,變成了第二行的props,由於props變化,第一行的組件需要使用新的props更新視圖,最終第一行變成了第二行的樣子。這是第二次render。
也就是說,“使用index作為key並且不會出問題”這種場景,是因為render了兩次,才最終達成了視圖的正確更新。
那什么時候可以復現
如果你去刪除第一行的過程中,只會觸發一次render,那么就會復現問題。也就是說,如果每一行的組件,不依賴於任何“響應式”數據,那么就不會有第二次render,問題就能復現!
上述兩種情況的DEMO:codesandbox.io/s/wonderful…
特殊情況:如果列表中的組件,是簡單的文本節點,文本節點沒有props,那么它會不會復現問題呢?
答案是“不會”,Vue的Diff過程對文本節點有特殊處理,不管key一不一樣,都會用“新的文本節點”覆蓋“舊的文本節點”。
結論
在使用非文本節點的組件,且這個組件沒有依賴於響應式的props,那么此時對於列表的刪除操作會導致視圖錯亂。
