React 組件的三種形式

[note: 本文基於 React v15.3.0+ 進行討論]html

通常來講,編寫 React 組件的方式有如下三種:react

  1. 無狀態組件(stateless component)。它是函數式的,不繼承於任何類;
  2. 繼承於 PureComponent 的組件;
  3. 繼承於 Component 的組件,這也是最常使用的組件形式。

那麼,這三種形式的使用場景及優劣各是什麼呢?git

無狀態組件

無狀態組件是經過函數定義的,好比下面這個最簡單的?:github

let Hello = (props) => <div>Hello {props.name}</div>

調用的時候,和日常組件的使用方式相同:redux

<Hello name="cjf" />

能夠看出,無狀態組件的最大特徵就是沒有內部狀態(廢話),因此無狀態組件的渲染結果徹底取決於輸入的 props數組

無狀態組件的優勢有如下幾個方面:less

  • 簡單;
  • 可複用性高。由於無狀態組件不包含內部狀態,也就是沒有內在邏輯,輸出徹底取決於輸入,因此複用組件只須要輸入不一樣的數據便可;
  • 單元測試更容易進行。由於邏輯都被移出了 view 層,因此單元測試時不須要渲染任何東西,能夠專一於單個邏輯。

缺點有如下兩點:函數

  • 無狀態組件中不能使用生命週期函數。若是必定要用的話,只能在外面包一層父組件,而後定義生命週期函數;
  • 沒法手動控制無狀態組件的從新渲染(re-render)。只要無狀態組件接收到了新的 props,它就會進行從新渲染。固然還有一點須要注意的是,無狀態組件對於 props 是淺比較的。

繼承於 PureComponent 的組件

這類組件的定義方式以下:post

class MyComponent extends PureComponent {...}

PureComponent 是繼承於 Component 類的,不一樣的是內部實現了 shouldComponentUpdate 的優化。它會淺比較組件內部 propsstate 的值,從而決定組件應不該該從新渲染,PureComponent 的使用能夠提升 React 應用的性能。性能

PureComponent 中,咱們不須要寫相似於

if (this.state.someVal !== computedVal) {
  this.setState({ someVal: computedVal })
}

的代碼來避免組件被重複渲染。

讓咱們看看源碼
當一個組件是 PureComponent 時,會執行下面操做來檢查是否須要 update

if (type.prototype && type.prototype.isPureReactComponent) {
  return (
    !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
  );
}

這裏用的也是淺比較(shallowEqual),因此對於多層嵌套的對象和數組中的變化都不會被檢測到。好比下面這個例子:

handleClick() {
  let { items } = this.state

  items.push('new-item')
  this.setState({ items })
}

render() {
  return (
    <div>
      <button onClick={::this.handleClick} />
      <ItemList items={ this.state.items } />
    </div>
  )
}

假設 ItemList 是一個 PureComponent,由於它執行的是淺比較,因此 this.state.items 的變化是不會觸發 ItemList 的更新的。若是要觸發更新,應該使用 setState 的另外一種調用形式,每次都返回一個新的對象:

handleClick() {
  this.setState(prevState => ({
    words: prevState.items.concat(['new-item'])
  }));
}

最後須要注意的是,在 PureComponent 中是不能本身定義的 shouldComponentUpdate() 方法的。若是實在有這個必要,只能使用 Component 組件。

繼承於 Component 的組件

沒啥說的,這就是最普通的組件形式。

後續

從上面的討論咱們能夠得出結論,在 React 應用中,應當儘量多的使用無狀態組件或 PureComponent 以加強複用性和提升性能。可是,在具體的項目實踐中,咱們每每須要經過 Ajax 請求獲取數據,並進一步對數據進行處理。爲了使組件的職責更加單一,引入了容器組件(Container Component)的概念。咱們能夠將數據獲取以及處理的邏輯放在容器組件中,而後將已處理的數據傳遞給展現組件,使得組件的耦合性進一步地下降。

react-redux 中的 connect() 就是容器組件的一種具體實現。

參考文獻:

  1. https://stackoverflow.com/que...
  2. https://facebook.github.io/re...
  3. https://github.com/eyasliu/bl...
  4. https://juejin.im/post/596d65...
  5. http://www.zcfy.cc/article/re...
  6. https://60devs.com/pure-compo...
  7. http://www.jianshu.com/p/980a...
相關文章
相關標籤/搜索