什么是Virtual DOM
Virtual DOM只是真實(shí)Dom的副本,它不是Javascript的標(biāo)準(zhǔn)概念,更像是專門為了React設(shè)計(jì)的概念,可以稱之為Virtual React DOM。它是一個(gè)節(jié)點(diǎn)樹(shù), 每個(gè)節(jié)點(diǎn)存儲(chǔ)了對(duì)應(yīng)節(jié)點(diǎn)的部分信息并且實(shí)現(xiàn)了React interfaces。部分與React相關(guān)的API也會(huì)存儲(chǔ)在Fiber結(jié)構(gòu)中,因此Fibers是Virtual DOM的組成部分。
節(jié)點(diǎn)樹(shù)主要是為了服務(wù)于Diff算法,最小化頁(yè)面更新,提升性能。
- 刷新頁(yè)面(比如通過(guò)setState)
- 生成節(jié)點(diǎn)樹(shù)
- Diff 算法
- 計(jì)算出minimal render operation
- render ( to DOM, iOS, or Android)
以上第一步到第四步均屬于reconciler,第五步屬于renderer
Diff Algorithm
React 如何使本該是 O(n3)的計(jì)算優(yōu)化成O(n)
- 首先檢查同級(jí)節(jié)點(diǎn)類型,如果節(jié)點(diǎn)類型發(fā)生改變,直接全部重新生成, 而且銷毀之前的節(jié)點(diǎn),之前的節(jié)點(diǎn)組件及其所有子組件componentWillUnmount觸發(fā), 新組件及其所有子組件UNSAFE_componentWillMount ,componentDidMount相繼觸發(fā)
- 如果節(jié)點(diǎn)類型相同,檢查節(jié)點(diǎn)屬性,僅更新發(fā)生改變的節(jié)點(diǎn)
- 如果子節(jié)點(diǎn)是list,默認(rèn)情況下(沒(méi)有 key),React會(huì)按序比較兩個(gè)列表,比如,列表末尾插入,React僅插入一個(gè)節(jié)點(diǎn),若列表頭插入,React會(huì)修改所有節(jié)點(diǎn)。
- 如果子節(jié)點(diǎn)是list,并且存在key,React在比較列表是,不會(huì)按序比較,而且類似比較key-element。
Element List with Index Key
日常開(kāi)發(fā)時(shí),有的小伙伴會(huì)使用index作為key,這是不太好的習(xí)慣,主要是因?yàn)閮牲c(diǎn):
- 如上所說(shuō),使用index作為key,list一旦重排(中間插入,末尾插入,中間刪除,混序)皆會(huì)導(dǎo)致不必要的其他list item的更新,耗費(fèi)性能
- 對(duì)于一組uncontrolled input list,加入順序發(fā)生變化,但兩個(gè)list實(shí)際上看不出差別,因此React不會(huì)更新,那么頁(yè)面上顯示的input順序也不會(huì)更新 demo