react效能優化

城府不落雪發表於2019-03-08

如果想提高效能就需要知道什麼地方會影響效能?

從過往的經驗和實踐中,影響網頁效能最大的因素就是瀏覽器的重繪和迴流,React背後的虛擬DOM就是儘可能的減少瀏覽器的重繪和迴流。

那在此之上,我們還能做什麼來防止不必要的渲染?

在這之前,先跟我一起了解下函數語言程式設計

什麼是函數語言程式設計?

函數語言程式設計起源於數學,假設我們定義一個加法的方法f,然後改變輸入為f(1,3),那麼無論這個方法的上下文,無論什麼時間呼叫多少次,返回結果都是4,用數學表達就是f(x,y) = z,給定輸入x,y作用在f上,始終結果是z

函數語言程式設計講究的三個原則:
1.相同的輸入得到相同的輸出
2.沒有副作用
3.不依賴外部的狀態(方法內的狀態都只在方法的生命週期記憶體活,不能在方法中使用共享變數,因為這樣會給方法帶來不可知對的因素)

那說了這麼多函數語言程式設計有什麼好處呢?

1、函數語言程式設計不依賴外部狀態這一特點,使得我們可以利用CPU在分散式叢集上做平行計算,這對於多種科學計算和資源密集型計算任務是非常核心的一點,讓計算機高效處理這類任務變的可能
2、相同的輸入得到相同對的輸出,這讓我們的程式碼變得可預測,可以非常方便的進行方法級別的測試。


說完函數語言程式設計,我們再回頭說說react的效能優化
《深入React技術棧中》這樣描述的“ react的設計是有函數語言程式設計的基因的,react元件本身就是純函式,react的createElement方法保證了元件是純淨的,即傳入相同的props得到一定的虛擬dom,整個過程可預測”。
那麼優化的時候我們可以考慮通過拆分元件為子元件,進而對元件進行更細粒度的控制。


那接下來就要考慮如何做更細粒度控制,避免多次無用渲染?

react官方有提供PureComponent類,凡是繼承自這個類的元件,react都會預設在shouldComponentUpdate中替你做這樣一件事,淺比較你的新傳入的props和state和現在的props,state。所謂的淺比較就是隻比較props和state中資料的引用地址,引用地址不改變就不會重新渲染。

很顯然,問題來了,如果我的資料結構巢狀很深,那豈不是會忽略掉深層次的資料變化,而導致頁面不渲染? 因此react官方提醒道,繼承PureComponent之前最好props,state的結構簡單,對於巢狀深的結構就不要繼承PureComponent了


那對於深層次的資料結構就這樣放棄使用puerRender了嗎?
答案當然不是了,不過先不急著說這個,我們先說對於結果簡單的可以繼承PureComponent的我們要注意些什麼

1、

  <MeetingList style = {{'width':'200px','height':'200px','overFlow':'hidden'}}>
  
  <Item items = {this.props.items.filter(item=>item.val>10)}>
複製程式碼

這種直接將props設定成物件或者陣列的方式,每次都會觸發重新渲染,哪怕值沒有改變。

原因在於每次呼叫react元件都會重新建立元件,就算傳入的陣列或物件值沒有改變,但是引用地址發生改變了。

解決方法,將物件提前賦值為常量,不直接使用字面量即可

2、

  <input onChange = this.change.bind(this)>
複製程式碼

設定props方法並通過bind繫結this的方式,每次都會觸發重新渲染

原因在於bind會返回一個函式,每次執行bind返回的函式的引用地址改變了

解決辦法採用箭頭函式

3、

class NameItem extends Component {
    render(){
        return (
        <Item >
         <span>a child</span>
         </Item>
        )
    }
}
 
複製程式碼

對於設定了子元件的react元件,每次都會重新渲染。

原因在於,元件編譯之後其實是這樣的

  <Item children = {React.createElement('span',{},'a child')}>
複製程式碼

children引用改變了,導致每次都會重新渲染

解決辦法讓NameItem(也就是Item的父元件)繼承pureComponent,根據淺比較策略不會對Item的children進行深比較,也就不會重新渲染


說完簡單的資料結構,我們再來說下對於props和state比較複雜的資料結構應該怎麼處理,答案是採用immutable。

簡單說下immutable
1.持久化資料儲存:對immutable物件進行修改的時候都會返回一個新的immutable物件,也就是使用舊資料建立新資料時,包證了舊資料可用

2.結構化共享:如果樹中一個節點變化,則只修改這個節點和受它影響的父節點,其他節點實現共享,避免了深拷貝帶來的效能問題

如何使用immutable實現pureRender?

答案是在shouldComponentUpdate中利用immutable進行深比較,拋棄之前的PureComponent的淺比較

import React from 'react';
import {is} from 'immutable';

class App extends Component {
 shouldComponentUpdate(nextProps,nextState){
   const thisProps = this.props || {};
   const thisState = this.state || {};
   if(Object.keys(thisProps).length !== Object.keys(nextProps).length ||
   Object.keys(thisState).length !== Object.keys(nextState).length){
       return true;
   }

   for(const key in nextProps){
     if(nextProps.hasOwnProperty(key) && !is(thisProps[key],nextProps[key])){
       return true;
     }
   }

   for(const key in nextState){
     if(nextState.hasOwnProperty(key) && !is(thisState[key],nextState[key])){
       return true;
     }
   }

   return false;

 }
}
複製程式碼

相關文章