vue和react項(xiàng)目中key的作用示例詳解
vue react對(duì)比新舊虛擬節(jié)點(diǎn)
vue和react都是采用diff算法來(lái)對(duì)比新舊虛擬節(jié)點(diǎn),從而更新節(jié)點(diǎn)。
在交叉對(duì)比中,當(dāng)新節(jié)點(diǎn)跟舊節(jié)點(diǎn)頭尾交叉對(duì)比沒(méi)有結(jié)果時(shí),會(huì)根據(jù)新節(jié)點(diǎn)的key去對(duì)比舊節(jié)點(diǎn)數(shù)組中的key,從而找到相應(yīng)的舊節(jié)點(diǎn)(這里對(duì)應(yīng)的是一個(gè)key=>index的map映射)。
如果沒(méi)有找到就認(rèn)為是一個(gè)新增節(jié)點(diǎn)。而如果沒(méi)有key,那么就會(huì)采用遍歷查找的方式去找到對(duì)應(yīng)的舊節(jié)點(diǎn),一種一個(gè)map映射,另一種是遍歷查找。相比而言,map映射速度更快。
vue部分源碼如下
//vue項(xiàng)目 src/core/vdom/patch.js -448行 //oldCh是一個(gè)舊虛擬節(jié)點(diǎn)數(shù)組 if(isUndef(oldKeyToIdx)){ oldKeyToIdx = createKeyToOldIdx(oldCh,oldStartIdx,oldEndIdx) } if(isDef(newStartVnode.key)){ //map方式獲取 idxInOld = oldKeyToIdx[newStartVnode.key] }else { //遍歷方式獲取 idxInOld = findIdxInOld(newStartVnode,oldCh,oldStartIdx,oldEndIdx) }
創(chuàng)建map函數(shù)
function createKeyToOldIdx(children,beginIdx,endIdx){ let i,key const map = {} for(i = beginIdx;i<=endIdx;i++){ key = children[i].key if(isDef(key)) map[key] = i } return map }
遍歷尋找
//sameVnode 是對(duì)比新舊節(jié)點(diǎn)是否相同的函數(shù) function findIdxInOld(node,oldCh,start,end){ for(let i = start;i<end;i++){ const c = oldCh[i] if(isDef(c) && sameVnode(node,c)) return i } }
上面的結(jié)論是基于沒(méi)有key的情況diff速度會(huì)更快。確實(shí),這種觀點(diǎn)沒(méi)有錯(cuò)。沒(méi)有綁定key的情況下,并且在遍歷模版簡(jiǎn)單的情況下,會(huì)導(dǎo)致虛擬新舊節(jié)點(diǎn)對(duì)比更快,節(jié)點(diǎn)也會(huì)復(fù)用。而這種復(fù)用是就地復(fù)用,一種鴨子辯型的復(fù)用。以下為簡(jiǎn)單的例子:
<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的內(nèi)容會(huì)生成以下的dom節(jié)點(diǎn)數(shù)組,我們給每一個(gè)節(jié)點(diǎn)標(biāo)記一個(gè)身份id:
[ '<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 ]
改變dataList數(shù)據(jù),進(jìn)行數(shù)據(jù)位置替換,對(duì)比改變后的數(shù)據(jù)
vm.dataList = [4,1,3,5,2]//數(shù)據(jù)位置替換 //沒(méi)有key的情況,節(jié)點(diǎn)位置不變,但是節(jié)點(diǎn)innerText內(nèi)容更新了 [ '<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節(jié)點(diǎn)位置進(jìn)行了交換,但是內(nèi)容沒(méi)有更新 // <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列表項(xiàng)
vm.dataList = [3,4,5,6,7] //數(shù)據(jù)進(jìn)行增刪 // 1、沒(méi)有key的情況,節(jié)點(diǎn)位置不變,內(nèi)容也更新了 [ '<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的情況,節(jié)點(diǎn)刪除了A B節(jié)點(diǎn),新增了F G節(jié)點(diǎn) // <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 ]
從以上來(lái)看,不帶有key,并且使用簡(jiǎn)單的模版,可以更有效的復(fù)用節(jié)點(diǎn),diff速度也是不帶key更加快速的,因?yàn)閹в衚ey在增刪節(jié)點(diǎn)上有耗時(shí)。這就是vue文檔所說(shuō)的默認(rèn)模式。但是這個(gè)并不是key作用,而是沒(méi)有key的情況下可以對(duì)節(jié)點(diǎn)就地復(fù)用,提高性能。
這種模式會(huì)帶來(lái)一些隱藏的副作用,比如可能不會(huì)產(chǎn)生過(guò)度效果,或者在某些節(jié)點(diǎn)有綁定數(shù)據(jù)(表單)狀態(tài),會(huì)出現(xiàn)狀態(tài)錯(cuò)位。vue文檔也說(shuō)明了這個(gè)模式是高效的,但是只是適用于不依賴(lài)子組件狀態(tài)或臨時(shí)dom狀態(tài)(例如:表單輸入值)的列表渲染輸出
但是key的作用是什么?
key是給每個(gè)vnode的唯一id,可以依靠key,更快的拿到oldVnode中對(duì)應(yīng)的vnode節(jié)點(diǎn)。
1、更準(zhǔn)確
因?yàn)閹ey就不是就地復(fù)用了,在sameNode函數(shù)a.key === b.key對(duì)比中可以避免就地服用的情況。所以會(huì)更加準(zhǔn)確。
2、更快
利用key的唯一性生成map對(duì)象來(lái)獲取對(duì)應(yīng)節(jié)點(diǎn),比遍歷方式更快。
以上就是vue和react項(xiàng)目中key的作用示例詳解的詳細(xì)內(nèi)容,更多關(guān)于vue react項(xiàng)目key作用的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
在Vue中實(shí)現(xiàn)父組件控制子組件的值的兩種方法
在Vue開(kāi)發(fā)中,父組件和子組件之間的數(shù)據(jù)傳遞是一項(xiàng)常見(jiàn)的任務(wù),本文將介紹如何在Vue中實(shí)現(xiàn)父組件控制子組件的值,以便靈活地管理和更新子組件的數(shù)據(jù),文中有詳細(xì)的代碼講解,需要的朋友可以參考下2023-11-11vue腳手架創(chuàng)建項(xiàng)目時(shí)報(bào)catch錯(cuò)誤及解決
這篇文章主要介紹了vue腳手架創(chuàng)建項(xiàng)目時(shí)報(bào)catch錯(cuò)誤及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01Vue高級(jí)用法實(shí)例教程之動(dòng)態(tài)組件
讓多個(gè)組件使用同一個(gè)掛載點(diǎn),并動(dòng)態(tài)切換,這就是動(dòng)態(tài)組件,下面這篇文章主要給大家介紹了關(guān)于Vue高級(jí)用法實(shí)例教程之動(dòng)態(tài)組件的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-11-11vue組件實(shí)現(xiàn)可搜索下拉框擴(kuò)展
這篇文章主要為大家詳細(xì)介紹了vue組件實(shí)現(xiàn)可搜索下拉框的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06VueX?mapGetters獲取Modules中的Getters方式
這篇文章主要介紹了VueX?mapGetters獲取Modules中的Getters方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08在Vue3中為路由Query參數(shù)標(biāo)注類(lèi)型的方法
這篇文章主要介紹了在Vue3中如何為路由Query參數(shù)標(biāo)注類(lèi)型,我們就針對(duì)這個(gè)話題如何為路由Query參數(shù)標(biāo)注類(lèi)型為例,看看Composable和IOC容器的代碼風(fēng)格究竟有什么不同,需要的朋友可以參考下2024-08-08vue.config.js中configureWebpack與chainWebpack區(qū)別及說(shuō)明
這篇文章主要介紹了vue.config.js中configureWebpack與chainWebpack區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09vue自定義指令和動(dòng)態(tài)路由實(shí)現(xiàn)權(quán)限控制
這篇文章主要介紹了vue自定義指令和動(dòng)態(tài)路由實(shí)現(xiàn)權(quán)限控制的方法,幫助大家更好的理解和學(xué)習(xí)vue,感興趣的朋友可以了解下2020-08-08vant的Loading加載動(dòng)畫(huà)組件的使用(通過(guò)接口拿數(shù)據(jù)時(shí)顯示加載狀態(tài))
這篇文章主要介紹了vant的Loading加載動(dòng)畫(huà)組件的使用,通過(guò)接口拿數(shù)據(jù)時(shí)顯示加載狀態(tài),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01