關(guān)于 react 中的 diff 算法的探究

寫這篇博客的初衷是為了加深自己對該知識點(diǎn)的理解,同時(shí)也是記錄一下自己的遇到的問題厦坛,避免自己以后再犯相同的錯(cuò)誤帖努。為了解釋清除這個(gè)問題,接下來我們先大概了解一下 react 中的 diff 算法粪般。

diff 的分類

tree diff(針對樹結(jié)構(gòu))

  • react 對兩棵樹進(jìn)行層次比較拼余,對第一層的比較結(jié)束,則接著比較下一層次亩歹,
  • 若某一節(jié)點(diǎn)消失了匙监,則該節(jié)點(diǎn)與其所有子節(jié)點(diǎn)會被完全刪除,不在進(jìn)行進(jìn)一步比較。

component diff(針對組件結(jié)構(gòu))

  • 首先判斷兩個(gè)組件是不是同一類型小作,若是同一類型亭姥,則繼續(xù)比較 Dom 樹,如果不是顾稀,則替換該組件下的所有子節(jié)點(diǎn)达罗。
  • 如果我們確切的知道組件是同一類型,并且它的虛擬dom沒有變化静秆。我們可以通過 shouldComponentUpdate() 來判斷該組件是否需要進(jìn)行 diff粮揉。從而節(jié)省大量的 diff 運(yùn)算時(shí)間。

element diff(針對元素結(jié)構(gòu))

該 diff 算法主要是針對同一層級的節(jié)點(diǎn)抚笔,react 對處于同一層級的節(jié)點(diǎn)提供了以下三種操作

  • 插入節(jié)點(diǎn): 新的節(jié)點(diǎn)不在原來該層級的 dom 節(jié)點(diǎn)集合中扶认,則執(zhí)行插入操作。
  • 移動(dòng)節(jié)點(diǎn):若某一節(jié)點(diǎn)在該層級原本 dom 集合中存在殊橙,并且新的dom集合中也存在辐宾,react 判斷他們?yōu)橥辉兀皇俏恢貌煌蚵瑒t僅僅移動(dòng)該節(jié)點(diǎn)叠纹。而 key 則是 react 判斷是否為同一元素的依據(jù)。
  • 刪除節(jié)點(diǎn):若該節(jié)點(diǎn)在該層級原本的 dom 集合存在敞葛,但新的 dom 集合中不存在誉察,則刪除該節(jié)點(diǎn),或者該層級原本的 dom 集合存在制肮,新的 dom 集合也存在冒窍,但react判斷他們并不是同一元素,也需要在原本的集合中刪除該節(jié)點(diǎn)豺鼻。

問題起因

某次頁面開發(fā)涉及到了節(jié)點(diǎn)的移動(dòng)综液,但我往其中插入某個(gè)新的節(jié)點(diǎn)的時(shí)候,發(fā)現(xiàn)整個(gè)頁面的數(shù)據(jù)出現(xiàn)了問題儒飒,經(jīng)過調(diào)試谬莹,發(fā)現(xiàn)新建的節(jié)點(diǎn)雖然在頁面中的位置是正確的,但它的 props 的 id 號確是頁面更新前這個(gè)節(jié)點(diǎn)的id號桩了。為了解釋清楚出現(xiàn)這個(gè)問題的原因附帽。我們先來了解一下react的中的key干了什么事情

react 中的 Key

react 中的 key 屬性,它是一個(gè)特殊的屬性井誉,它之于具有該屬性的組件或元素蕉扮,就像是身份證對于我們?nèi)艘粯樱且粋€(gè)唯一的身份標(biāo)識颗圣。一個(gè) key 對應(yīng)一個(gè)組件或者元素喳钟,具有相同的 key 的組件或元素,react 將之視為同一個(gè)組件或者元素在岂。

了解了 key 做了什么奔则,我們再回過頭看遇到的問題。我當(dāng)時(shí)遍歷數(shù)組的時(shí)候蔽午,用的 key 是數(shù)組下標(biāo)易茬。


上圖中綠色色塊的是我們新插入的元素塞耕。色塊上的數(shù)字代表 key 值舶吗,我們能很輕易的識別綠色的色塊是新加入的何吝。但 react 不這樣想敬拓。它的思路是這樣的蚊伞。

  • 灰色色塊key 為 1吏恭, 更新后的灰色色塊 key 也為 1埃难,沒問題绊袋,是同一個(gè)元素叠蝇,然后將更新后的灰色色塊 id 賦值為 1璃岳,下一位。
  • 米粉色色塊 key 為 2悔捶, 綠色色塊 key 也為 2铃慷, 嗯? 顏色不一樣誒蜕该,沒關(guān)系犁柜,key是一樣的,他倆就是同一個(gè)元素堂淡。于是將綠色色塊 id 賦值為 2馋缅。
    ... ... 以此類推
  • 最后來到了最后一個(gè)元素扒腕,key 為 6 的色塊沒有誒, 那就在這里插入一個(gè)新的節(jié)點(diǎn)。然后將新建的數(shù)據(jù)賦給它萤悴,至此 over瘾腰。
  • 將整個(gè)層級的 dom 比較完以后的 dom 就如下圖所示。

結(jié)果就是本應(yīng)該在2號位的數(shù)據(jù)到了6號位覆履。從而導(dǎo)致了頁面數(shù)據(jù)的異常蹋盆。

總結(jié)

如果當(dāng)涉及到遍歷的時(shí)候,頁面數(shù)據(jù)異常硝全,或者頁面與預(yù)期效果實(shí)現(xiàn)不一致栖雾,首先考慮是不是 key 值用了索引,所以伟众,為了養(yǎng)成習(xí)慣析藕,盡量避免使用索引做 key 值吧。官方也推薦我們這樣做凳厢。文章解釋得還不夠清楚噪径,后面有時(shí)間在做相應(yīng)的補(bǔ)充。

在最后数初,附上官網(wǎng)鏈接:https://zh-hans.reactjs.org/docs/lists-and-keys.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末找爱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子泡孩,更是在濱河造成了極大的恐慌车摄,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仑鸥,死亡現(xiàn)場離奇詭異吮播,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)眼俊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門意狠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人疮胖,你說我怎么就攤上這事环戈。” “怎么了澎灸?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵院塞,是天一觀的道長。 經(jīng)常有香客問我性昭,道長拦止,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮汹族,結(jié)果婚禮上萧求,老公的妹妹穿的比我還像新娘。我一直安慰自己顶瞒,他們只是感情好夸政,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著搁拙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪法绵。 梳的紋絲不亂的頭發(fā)上箕速,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機(jī)與錄音朋譬,去河邊找鬼盐茎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛徙赢,可吹牛的內(nèi)容都是我干的字柠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼狡赐,長吁一口氣:“原來是場噩夢啊……” “哼窑业!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起枕屉,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤常柄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后搀擂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體西潘,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年哨颂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了喷市。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡威恼,死狀恐怖品姓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情箫措,我是刑警寧澤缭黔,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站蒂破,受9級特大地震影響馏谨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜附迷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一惧互、第九天 我趴在偏房一處隱蔽的房頂上張望哎媚。 院中可真熱鬧,春花似錦喊儡、人聲如沸拨与。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽买喧。三九已至,卻和暖如春匆赃,著一層夾襖步出監(jiān)牢的瞬間淤毛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工算柳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留低淡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓瞬项,卻偏偏與公主長得像蔗蹋,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子囱淋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容