目錄
React diff 演算法
傳統diff 演算法
核心演算法
tree diff
為什麼要減少DOM節點的跨層級運算?
component diff
element diff
開發建議
React Lifecycle
React元件的3種狀態
狀態一:MOUNTING
狀態二:RECEIVE_PROPS
狀態三:UNMOUNTING
React生命周期总结
setState实现机制
开发建议
首頁 web前端 js教程 React框架有哪些演算法? react框架的演算法詳解

React框架有哪些演算法? react框架的演算法詳解

Sep 11, 2018 pm 02:58 PM
react 框架 演算法

本篇文章主要的講述了關於react框架的原理詳解,下面還有很多關於react的深入了解,現在就讓我們一起來看看這篇文章吧

#React 搞了2年多了,對這門框架可謂又愛又恨,它的優勢大家都熟知,但是缺點也漸漸暴露,一個大型項目裡,配合ReduxReactRouter等三方框架後,結合複雜的業務程式碼量會變得非常大(前端程式碼常常是以前的1.5倍)。如果前期底層設計得不好,時常面臨開發效率低的問題。下面歸納了一些React框架的核心概念,希望對大家有幫助:

React diff 演算法

React的diff演算法是Virtual DOM之所以任性的最大依仗,大家知道頁面的性能一般是由渲染速度和渲染次數決定,如何最大程度地利用diff演算法進行開發?我們先看看它的原理。

傳統diff 演算法

計算一棵樹形結構轉換成另一棵樹形結構的最少操作,傳統diff 演算法透過循環遞歸對節點進行依次對比,效率低下,演算法複雜度達到O(n^3),其中n 是樹中節點的總數。也就是說如果要展示1000個節點,就要依序執行上十億次的比較。這個效能消耗對對於前端專案來說是不可接受的。

核心演算法

如上所見,傳統 diff 演算法的複雜度為 O(n^3),顯然這是無法滿足效能要求的。而React透過制定大膽的策略,將 O(n^3) 複雜度的問題轉換成 O(n) 複雜度的問題。他是怎麼做到的?

tree diff

Web UI 中 DOM 節點跨層級的移動操作特別少,可以忽略不計。 React 對樹的演算法進行了簡潔明了的最佳化,即對樹進行分層比較,兩棵樹只會對同一層次的節點進行比較。如下圖所示:

React框架有哪些演算法? react框架的演算法詳解

React 透過updateDepth 對Virtual DOM 樹進行層級控制,只會對相同顏色方塊內的DOM 節點進行比較,即同一個父節點下的所有子節點。當發現節點已經不存在,則該節點及其子節點會被完全刪除掉,不會用於進一步的比較。這樣只需要對樹進行一次遍歷,便能完成整個 DOM 樹的比較。

// tree diff算法实现updateChildren: function(nextNestedChildrenElements, transaction, context) {
  updateDepth++;  var errorThrown = true;  try {    this._updateChildren(nextNestedChildrenElements, transaction, context);
    errorThrown = false;
  } finally {
    updateDepth--;    if (!updateDepth) {      if (errorThrown) {
        clearQueue();
      } else {
        processQueue();
      }
    }
  }
}
登入後複製

為什麼要減少DOM節點的跨層級運算?

如下圖,A 節點(包括其子節點)整個被移動到D 節點下,由於React 只會簡單的考慮同層級節點的位置變換,而對於不同層級的節點,只有建立和刪除操作。當根節點發現子節點中 A 消失了,就會直接銷毀 A;當 D 發現多了一個子節點 A,則會建立新的 A(包括子節點)作為其子節點。此時,React diff 的執行情況:create A -> create B -> create C -> delete A。

React框架有哪些演算法? react框架的演算法詳解

由此可發現,當節點跨層級移動時,並不會出現想像中的移動操作,而是以A 為根節點的樹被整個重新創建,這是一種影響React 效能的操作。

component diff

擁有相同類別的兩個元件將會產生相似的樹狀結構,擁有不同類別的兩個元件將會產生不同的樹形結構。

  • 如果是相同類型的元件,請依照原始策略繼續比較 virtual DOM tree

  • 如果不是,則將該元件判斷為 dirty component,從而替換整個元件下的所有子節點。

  • 對於同一類型的元件,有可能其Virtual DOM 沒有任何變化,如果能夠確切的知道這點那可以節省大量的diff 運算時間,因此React 允許使用者透過shouldComponentUpdate() 來判斷該元件是否需要進行diff。

React框架有哪些演算法? react框架的演算法詳解

如上圖,當component D 改變為component G 時,即使這兩個component 結構相似,一旦React 判斷D 和G 是不同類型的元件,就不會比較二者的結構,而是直接刪除component D,重新建立component G 以及其子節點。雖然當兩個component 是不同類型但結構相似時,React diff 會影響效能,但正如React 官方部落格所言:不同類型的component 是很少存在相似DOM tree 的機會,因此這種極端因素很難在實現開發過程中造成重大影響的。

element diff

對於同一層級的一組子節點,它們可以透過唯一 id 來區分。 React 提出最佳化策略:讓開發者對同一層級的同組子節點,增加唯一 key 進行區分,雖然只是小小的改動,但效能上卻發生了翻天覆地的變化!

新舊集合所包含的節點,如下圖所示,新舊集合進行diff 差異化對比,透過key 發現新舊集合中的節點都是相同的節點,因此無需進行節點刪除和創建,只需要將舊集合中節點的位置進行移動,更新為新集合中節點的位置,此時React 給出的diff 結果為:B、D 不做任何操作,A、C 進行移動操作,即可。

React框架有哪些演算法? react框架的演算法詳解

開發建議

(1)[基於tree diff] 開發元件時,保持穩定的DOM結構有助於維持整體的性能。換而言之,盡可能少地動態操作DOM結構,尤其是移動操作。當節點數過大或頁面更新次數過多時,頁面卡頓的現像比較明顯。可以透過 CSS 隱藏或顯示節點,而不是真的移除或新增 DOM 節點。

(2)[基於component diff] 開發元件時,請注意使用 shouldComponentUpdate() 來減少元件不必要的更新。除此之外,對於類似的結構應該盡量封裝成元件,既減少程式碼量,又能減少component diff的效能消耗。

(3)[基於element diff] 對於列表結構,盡量減少類似將最後一個節點移動到列表首部的操作,當節點數量過大或更新操作過於頻繁時,在一定程度上會影響React 的渲染效能。

React Lifecycle

React的生命週期具體可分為四種情況:

React框架有哪些演算法? react框架的演算法詳解

  • 當首次裝載元件時,依序執行getDefaultPropsgetInitialStatecomponentWillMountrendercomponentDidMount

  • ##當卸載元件時,執行componentWillUnmount

  • 當重新裝載元件時,此時會依序執行getInitialStatecomponentWillMountrendercomponentDidMount,但不執行getDefaultProps;

  • #當再次渲染元件時,元件接受到更新狀態,此時依序執行componentWillReceivePropsshouldComponentUpdatecomponentWillUpdaterendercomponentDidUpdate

React元件的3種狀態

狀態一:MOUNTING

mountComponent 負責管理生命週期中的 getInitialStatecomponentWillMountrendercomponentDidMount

React框架有哪些演算法? react框架的演算法詳解

狀態二:RECEIVE_PROPS

updateComponent 負責管理生命週期中的componentWillReceivePropsshouldComponentUpdate componentWillUpdaterendercomponentDidUpdate

React框架有哪些演算法? react框架的演算法詳解

狀態三:UNMOUNTING

unmountComponent 負責管理生命週期中的 componentWillUnmount。 (想看更多就到PHP中文網React參考手冊欄位學習)

先將狀態設定為UNMOUNTING,若有componentWillUnmount,則執行;如果此時在componentWillUnmount 中呼叫setState,是不會觸發reRender。更新狀態為 NULL,完成元件卸載作業。實作程式碼如下:

// 卸载组件unmountComponent: function() {
  // 设置状态为 UNMOUNTING
  this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING;  // 如果存在 componentWillUnmount,则触发
  if (this.componentWillUnmount) {    this.componentWillUnmount();
  }  // 更新状态为 null
  this._compositeLifeCycleState = null;  this._renderedComponent.unmountComponent();  this._renderedComponent = null;

  ReactComponent.Mixin.unmountComponent.call(this);
}
登入後複製

React生命周期总结

React框架有哪些演算法? react框架的演算法詳解

生命周期调用次数能否使用setState()
getDefaultProps1
getInitialState1
componentWillMount1
render>=1
componentDidMount1
componentWillReceiveProps>=0
shouldComponentUpdate>=0
componentWillUpdate>=0
componentDidUpdate>=0
componentWillUnmount1
componentDidUnmount1

setState实现机制

setStateReact框架的核心方法之一,下面介绍一下它的原理:

React框架有哪些演算法? react框架的演算法詳解

// 更新 statesetState: function(partialState, callback) {
  // 合并 _pendingState
  this.replaceState(
    assign({}, this._pendingState || this.state, partialState),
    callback
  );
},
登入後複製

当调用 setState 时,会对 state 以及 _pendingState 更新队列进行合并操作,但其实真正更新 state 的幕后黑手是replaceState

// 更新 statereplaceState: function(completeState, callback) {
  validateLifeCycleOnReplaceState(this);  // 更新队列
  this._pendingState = completeState;  // 判断状态是否为 MOUNTING,如果不是,即可执行更新
  if (this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING) {
    ReactUpdates.enqueueUpdate(this, callback);
  }
},
登入後複製

replaceState 会先判断当前状态是否为 MOUNTING,如果不是即会调用 ReactUpdates.enqueueUpdate 执行更新。

当状态不为 MOUNTINGRECEIVING_PROPS 时,performUpdateIfNecessary 会获取 _pendingElement_pendingState_pendingForceUpdate,并调用 updateComponent 进行组件更新。

// 如果存在 _pendingElement、_pendingState、_pendingForceUpdate,则更新组件performUpdateIfNecessary: function(transaction) {
  var compositeLifeCycleState = this._compositeLifeCycleState;  // 当状态为 MOUNTING 或 RECEIVING_PROPS时,则不更新
  if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING ||
      compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) {    return;
  }  var prevElement = this._currentElement;  var nextElement = prevElement;  if (this._pendingElement != null) {
    nextElement = this._pendingElement;    this._pendingElement = null;
  }  // 调用 updateComponent
  this.updateComponent(
    transaction,
    prevElement,
    nextElement
  );
}
登入後複製

如果在 shouldComponentUpdatecomponentWillUpdate 中调用 setState,此时的状态已经从 RECEIVING_PROPS -> NULL,则 performUpdateIfNecessary 就会调用 updateComponent 进行组件更新,但 updateComponent 又会调用 shouldComponentUpdatecomponentWillUpdate,因此造成循环调用,使得浏览器内存占满后崩溃。

开发建议

不建议在 getDefaultPropsgetInitialStateshouldComponentUpdatecomponentWillUpdaterendercomponentWillUnmount 中调用 setState,特别注意:不能在 shouldComponentUpdatecomponentWillUpdate中调用 setState,会导致循环调用。

本篇文章到这就结束了(想看更多就到PHP中文网React使用手册栏目中学习),有问题的可以在下方留言提问。

以上是React框架有哪些演算法? react框架的演算法詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

改進的檢測演算法:用於高解析度光學遙感影像目標檢測 改進的檢測演算法:用於高解析度光學遙感影像目標檢測 Jun 06, 2024 pm 12:33 PM

01前景概要目前,難以在檢測效率和檢測結果之間取得適當的平衡。我們研究了一種用於高解析度光學遙感影像中目標偵測的增強YOLOv5演算法,利用多層特徵金字塔、多重偵測頭策略和混合注意力模組來提高光學遙感影像的目標偵測網路的效果。根據SIMD資料集,新演算法的mAP比YOLOv5好2.2%,比YOLOX好8.48%,在偵測結果和速度之間達到了更好的平衡。 02背景&動機隨著遠感技術的快速發展,高解析度光學遠感影像已被用於描述地球表面的許多物體,包括飛機、汽車、建築物等。目標檢測在遠感影像的解釋中

PHP 框架的學習曲線與其他語言框架相比如何? PHP 框架的學習曲線與其他語言框架相比如何? Jun 06, 2024 pm 12:41 PM

PHP框架的學習曲線取決於語言熟練度、框架複雜性、文件品質和社群支援。與Python框架相比,PHP框架的學習曲線較高,而與Ruby框架相比,則較低。與Java框架相比,PHP框架的學習曲線中等,但入門時間較短。

PHP 框架的輕量級選項如何影響應用程式效能? PHP 框架的輕量級選項如何影響應用程式效能? Jun 06, 2024 am 10:53 AM

輕量級PHP框架透過小體積和低資源消耗提升應用程式效能。其特點包括:體積小,啟動快,記憶體佔用低提升響應速度和吞吐量,降低資源消耗實戰案例:SlimFramework創建RESTAPI,僅500KB,高響應性、高吞吐量

vue.js vs.反應:特定於項目的考慮因素 vue.js vs.反應:特定於項目的考慮因素 Apr 09, 2025 am 12:01 AM

Vue.js適合中小型項目和快速迭代,React適用於大型複雜應用。 1)Vue.js易於上手,適用於團隊經驗不足或項目規模較小的情況。 2)React的生態系統更豐富,適合有高性能需求和復雜功能需求的項目。

開創性CVM演算法破解40多年計數難題!電腦科學家擲硬幣算出「哈姆雷特」獨特單字 開創性CVM演算法破解40多年計數難題!電腦科學家擲硬幣算出「哈姆雷特」獨特單字 Jun 07, 2024 pm 03:44 PM

計數,聽起來簡單,卻在實際執行上很困難。想像一下,你被送到一片原始熱帶雨林,進行野生動物普查。每當看到一隻動物,就拍一張照片。數位相機只是記錄追蹤動物總數,但你對獨特動物的數量感興趣,卻沒有統計。那麼,若想獲取這獨特動物數量,最好的方法是什麼?這時,你一定會說,從現在開始計數,最後再從照片中將每一種新物種與名單進行比較。然而,這種常見的計數方法,有時並不適用於高達數十億條目的資訊量。來自印度統計研究所、UNL、新加坡國立大學的電腦科學家提出了一種新演算法——CVM。它可以近似計算長列表中,不同條

React在HTML中的作用:增強用戶體驗 React在HTML中的作用:增強用戶體驗 Apr 09, 2025 am 12:11 AM

React通過JSX與HTML結合,提升用戶體驗。 1)JSX嵌入HTML,使開發更直觀。 2)虛擬DOM機制優化性能,減少DOM操作。 3)組件化管理UI,提高可維護性。 4)狀態管理和事件處理增強交互性。

反應與前端:建立互動體驗 反應與前端:建立互動體驗 Apr 11, 2025 am 12:02 AM

React是構建交互式前端體驗的首選工具。 1)React通過組件化和虛擬DOM簡化UI開發。 2)組件分為函數組件和類組件,函數組件更簡潔,類組件提供更多生命週期方法。 3)React的工作原理依賴虛擬DOM和調和算法,提高性能。 4)狀態管理使用useState或this.state,生命週期方法如componentDidMount用於特定邏輯。 5)基本用法包括創建組件和管理狀態,高級用法涉及自定義鉤子和性能優化。 6)常見錯誤包括狀態更新不當和性能問題,調試技巧包括使用ReactDevTools和優

React與Vue:Netflix使用哪個框架? React與Vue:Netflix使用哪個框架? Apr 14, 2025 am 12:19 AM

NetflixusesAcustomFrameworkcalled“ Gibbon” BuiltonReact,notReactorVuedIrectly.1)TeamSperience:selectBasedonFamiliarity.2)ProjectComplexity:vueforsimplerprojects:reactforforforproproject,reactforforforcompleplexones.3)cocatizationneedneeds:reactoffipicatizationneedneedneedneedneedneeds:reactoffersizationneedneedneedneedneeds:reactoffersizatization needefersmoreflexibleise.4)

See all articles