通過PureRender和Immutable實現React中的效能優化

玄學醬發表於2018-06-26

簡要介紹:React中的render存在著不必要的渲染,可以通過Puer Render(PureComponent)來減少渲染的次數,但是Puer Render只是進行淺比較,無法實現深層物件上的效能優化。Pure Render結合Immutable可以減少渲染次數。

1 . React中的render

僅通過React中的render,存在著不必要的渲染,這種不必要的渲染分為兩大類。

(1)自身的state沒有改變

在React的render中,只要發生setState行為,就會去重新渲染,即使setState的屬性前後並沒有發生變化,比如:

class TestComponent extends React.Component{
  constructor(props){
    super(props);
    this.state={
      count:0
    }
  }
  componentDidMount(){
    let self=this;
    setTimeout(function(){
      self.setState({
        count:0
      })
    },1000)
  }
  componentDidUpdate(){
    console.log(`元件更新了`);
  }
  render(){
    return <div>1</div>
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在這個元件中,我們setState的值在前後並沒有發生改變,但是呼叫此元件會輸出:

//元件更新了
  • 1

說明只要setState發生了,即使值在前後沒有發生變化,元件也會重新render。

(2)父元件傳遞的props會引起所有子元件render

父元件中的值傳遞給子元件,即使某些子元件中不需要重新渲染,也會重新render。舉例來說,父元件為Father:

class Father extends React.Component{
  constructor(props){
    super(props);
    this.state={
      obj:{
        title:`test immutable`,
        childZero:{
          name:`childZero`,
          age:0
        },
        childOne:{
          name:`childOne`,
          age:1
        },
        childTwo:{
          name:`childTwo`,
          age:2
        }
      }
    }
  }
  componentDidMount(){
    let self=this;
    let {obj}=this.state;
    setTimeout(function(){
      self.setState({
        obj:obj
      })
    },1000)
  }
  render(){
    const {obj}=this.state;
    return <div>
             <ChildZero obj={obj}/>
             <ChildOne obj={obj}/>
             <ChildTwo obj={obj}/>
           </div>
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

父元件有3個子元件:

class ChildZero extends React.Component{
  constructor(props){
    super(props);
  }
  componentDidUpdate(){
    console.log(`childZero觸發了更新`)
  }
  render(){
    return <div>3</div>
  }
}
class ChildOne extends React.Component{
  constructor(props){
    super(props);
  }
  componentDidUpdate(){
    console.log(`childOne觸發了更新`)
  }
  render(){
    return <div>3</div>
  }
}
class ChildTwo extends React.Component{
  constructor(props){
    super(props);
  }
  componentDidUpdate(){
    console.log(`childTwo觸發了更新`)
  }
  render(){
    return <div>3</div>
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

我們在父元件的componentDidMout方法中,setState然後觀察子元件的更新情況,發現所有的子元件都會更新,具體輸出為:

//childZero觸發了更新
//childOne觸發了更新
//childTwo觸發了更新
  • 1
  • 2
  • 3

2 . Pure Render可以減少淺層物件上不必要的更新

通過定義元件為Pure Render可以通過淺層比較,減少不必要的更新。我們通過使用PureComponent。同樣的我們以1(1)中的為例:

class TestComponent extends React.PureComponent{
  constructor(props){
    super(props);
    this.state={
      count:0
    }
  }
  componentDidMount(){
    let self=this;
    setTimeout(function(){
      self.setState({
        count:0
      })
    },1000)
  }
  componentDidUpdate(){
    console.log(`元件更新了`);
  }
  render(){
    return <div>1</div>
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

通過PureComponent來代替Component,此時如果僅僅是淺層物件屬性,當setState前後屬性不變時,那麼就不會有不必要的渲染。但是對於深層物件而言,pure Render無法實現。

3 .通過Immutable實現深層物件的效能優化

Immutable實現了js中的不可變資料結構,immutable具有不可變性,永續性等特點,通過資料共享的方式,修改相應的屬性實現深度克隆的過程只會影響父類屬性。

通過immutablejs可以方便進行深層物件的“相等”判斷。在React的效能優化中,在生命週期函式shouldComponetUpdate中判斷在是否需要更新,進行前後props和前後state的深層比較。

shouldComponentUpdate(nextProps,nextState){
    //進行深層判斷使用immutable
    const thisProps=this.props;
    if(Object.keys(thisProps).length!==Object.keys(nextProps).length){
      return true;
    }

    for(const key in nextProps){
      console.log(is(thisProps[key],nextProps[key]));
      if(!is(thisProps[key],nextProps[key])){
        return true;
      }
    }
    return false;
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

如果返回true,那麼會進行render,如果返回false,就不會render,從而可以控制深層物件是否需要重新render,實現了效能的優化。

這裡使用immutable,主要是因為其擁有如下特點:

I)快,在深層對比物件(Map)或者陣列(List)是否相同,比深層克隆式的比較快

II)安全,指的是對所有immutable的增刪改查,都是增量,不會使得原始資料丟失

3.immutable的缺點

使用immutalbe也存在了一些缺點:

(1)immutablejs原始檔較大

(2)具有很強的侵入性

本文作者:小小小小小亮
本文釋出時間:2018年04月20日
本文來自雲棲社群合作伙伴CSDN,瞭解相關資訊可以關注csdn.net網站。


相關文章