欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

React 的調(diào)和算法Diffing 算法策略詳解

 更新時間:2021年12月29日 11:30:51   作者:秋墨江雪  
React的調(diào)和算法,主要發(fā)生在render階段,調(diào)和算法并不是一個特定的算法函數(shù),而是指在調(diào)和過程中,為提高構(gòu)建workInProcess樹的性能,以及Dom樹更新的性能,而采用的一種策略,又稱diffing算法

算法策略

React的調(diào)和算法,主要發(fā)生在render階段,調(diào)和算法并不是一個特定的算法函數(shù),而是指在調(diào)和過程中,為提高構(gòu)建workInProcess樹的性能,以及Dom樹更新的性能,而采用的一種策略,又稱diffing算法。 在React 的官網(wǎng)上描述“Diffing” 算法時,提到了“diffing two trees”,但是在源碼實現(xiàn)時,并不是創(chuàng)建好兩棵樹后,再從上往下的diffing這兩棵樹。這個diffing發(fā)生在搭建子節(jié)點時, 實際是新生成的ReactElement 與 current樹上fibe節(jié)點的diffing。 為了將diffing算法的時間復(fù)雜度控制在O(n)(樹diff的時間復(fù)雜度涉及到樹的編輯距離,可以看這里), 采用了如下策略:

只比較同層級的節(jié)點,(貌似這一點沒有在官網(wǎng)中提到)

對于單節(jié)點比較,如果當(dāng)前節(jié)點type 和 key 不相同,不再比較其下子節(jié)點,直接刪掉該節(jié)點及其下整棵子樹,根據(jù)ReactElement重新生成節(jié)點樹。因為React認(rèn)為不同類型的組件生成的樹形結(jié)構(gòu)不一樣,不必復(fù)用。

如果子節(jié)點是數(shù)組,可根據(jù)唯一的key值定位節(jié)點進(jìn)行比較,這樣即使子節(jié)點順序發(fā)生變化,也可以根據(jù)key值進(jìn)行復(fù)用。

值得注意的是,所有節(jié)點的diffing都會比較key,key 默認(rèn)值為null。若是沒有設(shè)置,則null是恒等于null的,認(rèn)為key是相同的。

單節(jié)點diffing

單個節(jié)點進(jìn)行diffing時,會diffing兩組屬性:fibe.elementType vs ReactElement.type , fibe.key vs ReactElement.key, 如果這兩組屬性都相等,數(shù)據(jù)結(jié)構(gòu)的物理空間會有如下復(fù)用邏輯(詳見源碼reconcileSingleElement函數(shù)):

  1. 如果current fibe 存在 alternate 節(jié)點,(這意味著這個fibe節(jié)點之前參與過調(diào)和),則復(fù)用該alternate節(jié)點的物理空間;否則需要clone current fibe節(jié)點,占用新的物理空間
  2. 對應(yīng)的instance 或者 Dom 會被復(fù)用
  3. current fibe 下的child樹也會被直接掛載過來(下一步遞歸子節(jié)點時,會被使用)

如果兩組屬性有一個不相等:

  • fibe 根據(jù)ReactElement重新創(chuàng)建
  • 對應(yīng)的instance和Dom 也會重建
  • child 樹全部刪除。

如果生成的ReactElement 是單節(jié)點,但是對應(yīng)的current樹上是多節(jié)點時,會從逐一查找有沒有匹配的,找到匹配的,其他的都刪除;找不到,全部刪除。例如Couter組件有如下邏輯:當(dāng)點擊次數(shù)大于10時,隱藏點擊按鈕。當(dāng)?shù)竭_(dá)第10次時,span節(jié)點會被復(fù)用。

class Counter extends React.Component{
    state={
        count:0
    }
    addCount = ()=>{
        const count = this.state.count+1;
        this.setState({count})
    }
    componentDidUpdate(){
        console.log("updated")
    }
    render(){
        return this.state.count < 10 ? [
            <button onClick={this.addCount}>點擊</button>
            <span>點擊次數(shù):{this.state.count}</span>
        ]:<span>點擊次數(shù):{this.state.count}</span>;
    }
}

數(shù)組節(jié)點diffing

數(shù)組節(jié)點進(jìn)行diffing時,流程比較復(fù)雜:(源碼見reconcileChildrenArray函數(shù))

中間有兩次重要的遍歷,第一次按index遍歷,新舊節(jié)點依次比較,遇到key值不匹配的立即中斷遍歷。 第二次遍歷,對剩下的舊節(jié)點建立 “key - 節(jié)點”的Map表,遍歷剩下的新節(jié)點,按key值從表中查找舊節(jié)點進(jìn)行比較。以下是三種case下,新舊節(jié)點匹配比較的情況。

key值的使用要求

從單節(jié)點和數(shù)組節(jié)點的diffing上看,key值主要是為了減少新建。為了保證diffing時新建舊節(jié)點能匹配上,key值使用時有如下注意:

  1. 得穩(wěn)定,如果key值每次都變化(比如使用了隨機(jī)數(shù)),diffing時,新舊節(jié)全部匹配不上,將會引起大量的新建;
  2. 必須得唯一,如果key值不唯一,在建立“key - 節(jié)點”的Map表時,會遺漏和錯亂,導(dǎo)致頁面更新錯誤。

對于單節(jié)點,diffing時key值也會用到,不要認(rèn)為其沒用隨便亂設(shè)置。 也有一些不規(guī)范的用法,對單節(jié)點使用key值來實現(xiàn)組件的銷毀和重建,但這種用法是不符合React的設(shè)計理念的。

例如,有一個日志組件,內(nèi)部拉取日志數(shù)據(jù),對外部沒有數(shù)據(jù)依賴。但是在需求迭代時,在同頁面增加了審批操作,審批后,后端會新增一條日志數(shù)據(jù),這時候會希望前端頁面實時的展示新增的日志數(shù)據(jù),會需要觸發(fā)日志組件重新拉取數(shù)據(jù)。如果不使用向上提升數(shù)據(jù)的方式來解決問題,可以給該組件指定一個隨機(jī)的key,當(dāng)審批操作完成時,修改key值,則組件就會重新構(gòu)建。但這種方式的開銷較高,整個組件樹都會銷毀重建??梢圆捎闷渌鉀Q方案代替,例如可以給該組件指定ref,當(dāng)審批完成后,通過ref調(diào)用該組件的刷新函數(shù),重新獲取數(shù)據(jù),更新組件。

對于數(shù)組節(jié)點,key值主要是在子節(jié)點位置發(fā)生大的錯位時,會起到關(guān)鍵作用。 對于普通的末尾新增,和末尾刪除,第一次index遍歷就可以匹配完,不會進(jìn)入第二次key map的遍歷。 因為key值對“穩(wěn)定”和“唯一”性這兩個要求,一般前端會需要后端對list數(shù)據(jù)提供一個唯一標(biāo)識,對于聚合接口,會給后端增加額外工作,這種情況,可以先了解數(shù)據(jù)的變化特性,再決定是否真的需要設(shè)置key。

對于上面的日志組件,日志是一個列表,新增的日志,都是插在第一行,如果不設(shè)置key,基本上所有的子節(jié)點都要更新。如果設(shè)置key,就需要后端服務(wù)為每一條日志增加“永遠(yuǎn)”惟一的標(biāo)識符,例如id。曾經(jīng)經(jīng)歷過一次因為key值的唯一性變化,導(dǎo)致數(shù)據(jù)更新時頁面展示錯誤的案例。

到此這篇關(guān)于React 的調(diào)和算法(Diffing 算法)的文章就介紹到這了,更多相關(guān)React Diffing 算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • react 權(quán)限樹形結(jié)構(gòu)實現(xiàn)代碼

    react 權(quán)限樹形結(jié)構(gòu)實現(xiàn)代碼

    這篇文章主要介紹了react 權(quán)限樹形結(jié)構(gòu)實現(xiàn)代碼,項目背景react + ant design,本文結(jié)合實例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2024-05-05
  • React優(yōu)雅的封裝SvgIcon組件示例

    React優(yōu)雅的封裝SvgIcon組件示例

    這篇文章主要為大家介紹了React優(yōu)雅的封裝SvgIcon組件示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • React中的ref屬性的使用示例詳解

    React中的ref屬性的使用示例詳解

    React 提供了 refrefref 屬性,讓我們可以引用組件的實例或者原生 DOM 元素,使用 refrefref,可以在父組件中調(diào)用子組件暴露出來的方法,或者調(diào)用原生 element 的 API,這篇文章主要介紹了React中的ref屬性的使用,需要的朋友可以參考下
    2023-04-04
  • 在Create React App中啟用Sass和Less的方法示例

    在Create React App中啟用Sass和Less的方法示例

    這篇文章主要介紹了在Create React App中啟用Sass和Less的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • react native 原生模塊橋接的簡單說明小結(jié)

    react native 原生模塊橋接的簡單說明小結(jié)

    這篇文章主要介紹了react native 原生模塊橋接的簡單說明小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • React 高階組件HOC用法歸納

    React 高階組件HOC用法歸納

    高階組件就是接受一個組件作為參數(shù)并返回一個新組件(功能增強(qiáng)的組件)的函數(shù)。這里需要注意高階組件是一個函數(shù),并不是組件,這一點一定要注意,本文給大家分享React 高階組件HOC使用小結(jié),一起看看吧
    2021-06-06
  • React?Hooks的useState、useRef使用小結(jié)

    React?Hooks的useState、useRef使用小結(jié)

    React Hooks 是 React 16.8 版本引入的新特性,useState和useRef是兩個常用的Hooks,本文主要介紹了React?Hooks的useState、useRef使用,感興趣的可以了解一下
    2024-01-01
  • React中使用TS完成父組件調(diào)用子組件的操作方法

    React中使用TS完成父組件調(diào)用子組件的操作方法

    由于在項目開發(fā)過程中,我們往往時需要調(diào)用子組件中的方法,這篇文章主要介紹了React中使用TS完成父組件調(diào)用子組件,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • mobx在react hooks中的應(yīng)用方式

    mobx在react hooks中的應(yīng)用方式

    這篇文章主要介紹了mobx在react hooks中的應(yīng)用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • 關(guān)于getDerivedStateFromProps填坑記錄

    關(guān)于getDerivedStateFromProps填坑記錄

    這篇文章主要介紹了關(guān)于getDerivedStateFromProps填坑記錄,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06

最新評論