React組件性能優化總結

性能優化的思路

影響網頁性能最大的因素是瀏覽器的重排(repaint)和重繪(reflow)。react

React的Virtual DOM就是儘量地減小瀏覽器的重排和重繪。數組

從React渲染過程來看,如何防止沒必要要的渲染是解決問題的關鍵。瀏覽器

性能優化的具體辦法

1. 儘可能多使用無狀態函數構建組件

無狀態組件只有props和context兩個參數。它不存在state,沒有生命週期方法,組件自己即有狀態組件構建方法中的render方法。性能優化

在合適的狀況下,都應該必須使用無狀態組件。無狀態組件不會像React.createClass和ES6 class會在調用時建立新實例,它建立時始終保持了一個實例,避免了沒必要要的檢查和內存分配,作到了內部優化。數據結構

2. 拆分組件爲子組件,對組件作更細粒度的控制

相關重要概念: 純函數

純函數的三大構成原則:dom

  • 給定相同的輸入,它老是返回相同的輸出: 好比反例有 Math.random(), New Date()
  • 過程沒有反作用:即不能改變外部狀態
  • 沒有額外的狀態依賴:即方法內部的狀態都只能在方法的生命週期內存活,這意味着不能在方法內使用共享的變量。

純函數很是方便進行方法級別的測試及重構,它可讓程序具備良好的擴展性及適應性。純函數是函數式變成的基礎。函數

React組件自己就是純函數,即傳入指定props獲得必定的Virtual DOM,整個過程都是可預測的。性能

具體辦法

拆分組件爲子組件,對組件作更細粒度的控制。保持純淨狀態,可讓方法或組件更加專一(focus),體積更小(small),更獨立(independent),更具備複用性(reusability)和可測試性(testability)。測試

3. 運用PureRender,對變動作出最少的渲染

相關重要概念: PureRender

PureRender的Pure便是指知足純函數的條件,即組件被相同的props和state渲染會獲得相同的結果。優化

在React中實現PureRender須要從新實現shouldComponentUpdate生命週期方法。shouldComponentUpdate是一個特別的方法,它接收須要更新的props和state,其本質是用來進行正確的組件渲染。當其返回false的時候,再也不向下執行生命週期方法;當其返回true時,繼續向下執行。

組件在初始化過程當中會渲染一個樹狀結構,當父節點props改變的時候,在理想狀況下只需渲染一條鏈路上有關props改變的節點便可;可是,在默認狀況下shouldComponentUpdate方法返回true,React會從新渲染全部的節點

有一些官方插件實現了對shouldComponentUpdate的重寫,而後本身也能夠作一些代碼的優化來運用PureRender。

具體辦法

(1) 運用PureRender

使用官方插件react-addons-pure-render-mixin實現對shouldComponentUpdate的重寫

import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
  }
  render() {
    return <div className={this.props.className}>foo</div>
  }
}

它的原理是對object(包括props和state)作淺比較,即引用比較,非值比較。好比只用關注props中每個是否全等(若是是prop是一個對象那就是隻比較了地址,地址同樣就算是同樣了),而不用深刻比較。

(2)優化PureRender

避免不管如何都會觸發shouldComponentUpdate返回true的代碼寫法。

避免直接爲prop設置字面量的數組和對象

就算每次傳入的數組或對象的值沒有變,但它們的地址也發生了變化。

如如下寫法每次渲染時style都是新對象都會觸發shouldComponentUpdate爲true:

<Account style={{color: 'black'}} />

改進辦法:將字面量設置爲一個引用:

const defaultStyle = {};
<Account style={this.props.style || defaultStyle} />
避免每次都綁定事件

若是這樣綁定事件的話每次都要生成一個新的onChange屬性的值:

render() {
  return <input onChange={this.handleChange.bind(this)} />
}

應該儘可能在構造函數內進行綁定,若是綁定須要傳參那麼應該考慮抽象子組件或改變現有數據結構:

constructor(props) {
  super(props);
  this.handleChange = this.handleChange.bind(this);
}
handleChange() {
  ...
}
render() {
  return <input onChange={this.handleChange} />
}
在設置子組件的時候要在父組件級別重寫shouldComponentUpdate

4.運用immutable

JavaScript中對象通常是可變的,由於使用引用賦值,新的對象的改變將影響原始對象。爲了解決這個問題是使用深拷貝或者淺拷貝,但這樣作又形成了CPU和內存的浪費。

Immutable data很好地解決了這個問題。

Immutable data就是一旦建立,就不能再更改的數據。對Immutable對象進行修改、添加或刪除操做,都會返回一個新的Immutable對象。Immutable實現的原理是持久化的數據結構。即便用舊數據建立新數據時,保證新舊數據同時可用且不變。同時爲了不深拷貝帶來的性能損耗,Immutable使用告終構共享(structural sharing),即若是對象樹中一個節點發生變化,只修改這個節點和受它影響的父節點,其餘節點則進行共享。

相關文章
相關標籤/搜索