搜尋
首頁web前端js教程React元件的效能優化方法

React元件的效能優化方法

Mar 05, 2018 am 09:32 AM
react最佳化方法

1. 單一React元件的效能最佳化

React利用Virtual DOM來提升渲染效能,雖然每一次頁面更新都是最元件的從新渲染,但並不是將之前的渲染內容全部拋棄重來,借助Virtual DOM,React能夠計算出對DOM樹的最少修改,這就是React默認情況下渲染都很迅速的秘訣;

不過,雖然Virtual DOM能夠將每次DOM操作量減少到最小,但,計算和比較Virtual DOM依然是一個複雜的過程;

當然,如果能夠在開始計算Virtual DOM之前就判斷渲染的結果不會有變化,那麼就可以不進行Virtual DOM計算和比較,速度就會更快。

2.shouldComponentUpdate的預設實作方式

既然可以對元件在開始計算Virtual DOM之前判斷渲染結果不會有變化時,阻止渲染的進行,從而提升效能,那麼我們自然想到使用shouldComponentUpdate(nextProp,nextState)

shouldComponentUpdate函數在render函數之前調用,決定「什麼時候不需要從新渲染」;

即傳回一個布林值,決定更新是否進行下去,預設回傳true,若回傳false則中斷更新;


shouldComponentUpdate(nextProp,nextState){
  return (nextProp.completed !== this.props.completed) ||
    (nextProp.text !== this.props.text)
}

其中nextProps為此次更新傳入的props,對於這個元件,影響渲染內容的prop只有completed和text,只要確保這兩個prop沒有變化,shouldComponentUpdate就可以返回false阻止沒必要的更新

#但是,上述的比較只是'淺層比較',如果類型是基本類型,只要值相同,那麼“淺層比較”

也會認為二者相同:

#那,如果prop的型別是複雜的物件怎麼辦?

對於複雜對象,'淺層比較'的方式只看這兩個prop是不是同一個對象的引用,如果不是,哪怕對像中的內容完全一樣也會認為是不同的兩個prop。那麼使用“深層比較”:但對物件的結構是無法預測的,如果遞歸對每個字段都進行“深層比較”,不光會讓程式碼更加複雜,也可能會造成效能問題。

所以,要判斷前後的物件類型的prop是相同的,就必須保證prop是指向同一個JavaScript物件:


<Foo styleProp = {{color: "red"}}>

要避免使用上面的傳入方式,應為每次渲染都會重新建立{color: "red"}對象,引用位址每次都不同,將導致每次的styleProp都不同。


const footStyle = {color: "red"};//确保这个初始化只执行一次,不要放在render函数中
<Foo styleProp = {footStyle}>

使用‘單例模式'確保傳入的styleProp指向同一個物件

如果是函數呢?


<Foo onToggle={() => onToggleTodo(item.id)}/>

應該避免使用上面的函數傳遞模式,因為這裡賦值的是匿名函數,而且是在賦值的時候產生的,也就是說每次渲染都會產生一個新的函數,這就是問題所在。

如果要傳遞的prop很多呢?

恩~~用React-Redux的話,有對shouldComponentUpdate的預設實作。

3. 對多個React元件的效能最佳化

#當一個React元件被裝載、更新和卸載時,元件的一個序列生命週期函數會被呼叫。不過,這些生命週期函數是針對一個特定的React元件函數,在一個應用程式中,從上而下有許多React元件組合起來,它們之間的渲染過程要更加複雜。

同樣一個元件的渲染過程也要考慮三個流程:裝載階段、更新階段、卸載階段

對於裝載階段,元件無論如何都要徹底渲染一次,從這個React元件往下的所有子元件,都要經歷一遍React元件的裝載生命
週期,所以並沒有太多優化的事情可做。

對於卸載階段,只有一個生命週期函數componentWillUnmount,這個函數只是清理componentDidMount新增的事件處理監聽等收尾工作,所以,也沒有什麼可優化的空間;

4. React更新階段的調和(Reconciliation)過程

在元件更新過程,會建立更新Virtual DOM,並將其與先前的Virtual DOM進行比較,從而找出不同之處,使用最少的DOM操作進行更新

調和過程:即React更新中對Virtual DOM找不同的過程,通常對比兩個N個節點的樹形結構的演算法,時間複雜度是O(n*3),如果直接

使用預設對比,節點過多的話,需要操作的數量太多,而React不可能採用這種演算法;

React實際採用的演算法時間複雜度是O(N)(時間複雜度只是對一個演算法最好和最差情況下需要的指令操作數量級的估量)

React的Reconciliation演算法並不複雜,首先檢查兩個樹狀圖的根節點的類型是否相同,根據相同或不同有不同的處理方式:

##節點類型不同的情況

如果树形节点的类型不相同,那就意味着改动很大,直接认为原来的那个树形结构已经没用,可以扔掉,需要从新构建DOM树,原有的树形上的React组件便会经历“卸载”的生命周期;

也就是说,对于Virtual DOM树这是一个“更新”过程,但是却可能引发这个树结构上某些组件的“装载”和“卸载”过程
如:

更新前


 <p>
  <Todos />
 </p>

我们想要更新成这样:


 <span>
   <Todos />
 </span>

>1. 那么在作比较的时候,一看根节点原来是p,新的是span,类型就不一样了,那么这个算法就废弃之前的p包括里面的所有子节点,从新构建一个span节点和子节点;

>2. 很明显因为根节点不同就将所有的子节点从新构建,这很浪费,但是为了避免O(N*3)的时间复杂度,React这能选择这种比较简单、快捷的方法;

>3. 所以,作为开发者,我们一定要避免上面的浪费的情景出现

节点类型相同的情况

如果两个节点类型相同时,对于DOM元素,React会保留节点对应的DOM元素,只对其节点的属性和内容做对比,然后只修改更新的部分;

节点类型相同时,对于React组件类型,React做得是根据新节点的props去更新节点的组件实例,引发组件的更新过程;

在处理完根节点对比后,React的算法会对根节点的每一个子节点重复一样的操作

多个相同子组件的情况

如果最初组件状态为:


<ul>
  <TodoItem text = "First" />
  <TodoItem text = "Second" />

</ul>

更新后为:


<ul>
  <TodoItem text = "First" />
  <TodoItem text = "Second" />
  <TodoItem text = "Third" />
</ul>

那么React会创建一个新的TodoItem组件实例,而前两个则进行正常的更新过程但是,如果更新后为:


<ul>
  <TodoItem text = "Zero" />
  <TodoItem text = "First" />
  <TodoItem text = "Second" />

</ul>

(这将暴露一个问题)理想处理方式是,创建一个新的TodoItem组件实例放在第一位,后两个进入自然更新过程
但是要让react按照这种方式,就必须找两个子组件的不同之处,而现有计算两个序列差异的算法时间是O(N*2),显然则
不适合对性能要求很高的场景,所以React选择了一个看起来很傻的办法,即挨个比较每个子组件;

React首先认为把text为First的组件的text改为Zero,Second的改为First,最后创建一个text为Second的组件,这样便会破原有的两个组件完成一个更新过程,并创建一个text为Second的新组件

这显然是一个浪费,React也意到,并提供了方克服,不过需要开发人员提供一点帮助,这就是key

Key的使用

key属性可以明确的告诉React每个组件的唯一标识

如果最初组件状态为:


<ul>
  <TodoItem key={1} text = "First" />
  <TodoItem key={2} text = "Second" />

</ul>

更新后为:


<ul>
  <TodoItem key={0} text = "Zero" />
  <TodoItem key={1} text = "First" />
  <TodoItem key={2} text = "Second" />
</ul>

因为有唯一标识key,React可以根据key值,知道现在的第二和第三个组件就是之前的第一和第二个,便用原来的props启动更新过程,这样shouldComponentUpdate就会发生作用,避免无谓的更新;

注意:因为作为组件的唯一标识,所以key必须唯一,且不可变

下面的代码是错误的例子:


<ul>
  todos.map((item,index) => {
      <TodoItem
        key={index}
        text={item.text}
      />
    })
</ul>

使用数组下标作为key值,看起来唯一,但不稳定,因为随着todos数组值的不同,同样一个组件实例在不同的更新过程中数组的下标完全可能不同,把下标当做可以就会让React乱套,记住key不仅要唯一还要确保稳定不可变

需要注意:虽然key是一个prop,但是接受key的组件不能读取key的值,因为key和ref是React保留的两个特殊prop,并没有预期让组将直接访问。

相关推荐:

关于React组件项目实践

React组件性能优化方法解答

分解React组件的几种进阶方法

以上是React元件的效能優化方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
Python和JavaScript的未來:趨勢和預測Python和JavaScript的未來:趨勢和預測Apr 27, 2025 am 12:21 AM

Python和JavaScript的未來趨勢包括:1.Python將鞏固在科學計算和AI領域的地位,2.JavaScript將推動Web技術發展,3.跨平台開發將成為熱門,4.性能優化將是重點。兩者都將繼續在各自領域擴展應用場景,並在性能上有更多突破。

Python vs. JavaScript:開發環境和工具Python vs. JavaScript:開發環境和工具Apr 26, 2025 am 12:09 AM

Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。

JavaScript是用C編寫的嗎?檢查證據JavaScript是用C編寫的嗎?檢查證據Apr 25, 2025 am 12:15 AM

是的,JavaScript的引擎核心是用C語言編寫的。 1)C語言提供了高效性能和底層控制,適合JavaScript引擎的開發。 2)以V8引擎為例,其核心用C 編寫,結合了C的效率和麵向對象特性。 3)JavaScript引擎的工作原理包括解析、編譯和執行,C語言在這些過程中發揮關鍵作用。

JavaScript的角色:使網絡交互和動態JavaScript的角色:使網絡交互和動態Apr 24, 2025 am 12:12 AM

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C和JavaScript:連接解釋C和JavaScript:連接解釋Apr 23, 2025 am 12:07 AM

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

從網站到應用程序:JavaScript的不同應用從網站到應用程序:JavaScript的不同應用Apr 22, 2025 am 12:02 AM

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python vs. JavaScript:比較用例和應用程序Python vs. JavaScript:比較用例和應用程序Apr 21, 2025 am 12:01 AM

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C/C在JavaScript口譯員和編譯器中的作用C/C在JavaScript口譯員和編譯器中的作用Apr 20, 2025 am 12:01 AM

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

See all articles

熱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

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

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具