【譯】什麼時候使用Component或PureCompoent?

原文- When to use Component or PureComponentgit

tldr;優先使用PureComponent,而且永遠不要改變數據對象(或者使用其它最佳實踐)github

什麼時候使用Component或PureComponent?

我使用PureComponent已經有一段時間,這基於它是一個更具性能的組件版本。redux

事實證實這是真的,可是性能優點帶來了一些必要前提。數組

咱們來深刻研究PureComponent而且理解爲何咱們應該去使用它。緩存

ComponentPureComponent只有一個區別

PureComponentComponent幾乎徹底同樣,惟一的區別是PureComponent爲你處理shouldComponentUpdate事件。安全

propsstate發生變化,PureComponent會對二者都作淺比較;而Component則不會對二者的新舊值進行比較。因此,不管什麼時候調用shouldComponentUpdate,組件都會默認觸發re-renderasync

譯者注:shouldComponentUpdate默認返回true,必定觸發re-render函數

淺比較 101

當對propsstate的新舊值進行比較時,淺比較只會檢查基本數據類型的值是否相等(好比:1等於1或者true等於true),複雜如對象數組也是如此,不過是去比較引用值工具

不要改變數據

你可能聽過,不要對propsstate中的對象數組進行改變。若是你在父組件對對象進行了改變,你的子組件並不會更新。儘管上游的值發生了改變,可是子組件只會對props進行引用值的比較而且沒法檢測到區別。post

譯者注:這裏改變,指不改變對象引用的操做

而正確的作法是,藉助ES6object新特性、array擴展運算符或者使用不可變工具庫來返回新對象

譯者注:這裏改變,指改變對象引用的操做

以上操做會形成性能問題嗎?

基本數據類型的值和引用數據類型引用值比較是個極其廉價的操做。若是你有一組子組件列表而且其中一個更新了,相比於從新渲染全部,在每個子組件上進行propsstate的比較仍然是一個很是快的過程。

其餘一些注意點

不要在render中的函數綁定值

好比你父組件裏面有一組子組件列表,每個都傳給父組件方法一個惟一的參數。爲了綁定這個參數,你可能這樣作:

<CommentItem likeComment={() => this.likeComment(user.id)} />
複製代碼

問題是每一次父組件的render方法調用時,一個新函數(伴隨着新的引用)就會被建立而且傳遞給likeComment屬性。這會致使一些反作用:每個子組件的props都發生改變,最終致使他們所有從新渲染,哪怕數據自己並無發生變化。

解決這個問題的方法是,僅僅傳入父組件原型鏈方法的引用給子組件。子組件的likeComment屬性永遠都有相同的引用值而且永遠不會引發沒必要要的re-render

<CommentItem likeComment={this.likeComment} userID={user.id} />
複製代碼

那麼子組件僅須要建立一個類方法而且引用它的props便可:

class CommentItem extends PureComponent {
  ...
  handleLike() {
    this.props.likeComment(this.props.userID)
  }
  ...
}
複製代碼

不要在render方法中獲取數據

考慮你的profile組件須要顯示用戶的10個最受歡迎的文章:

render() {
  const { posts } = this.props
  const topTen = posts.sort((a, b) => b.likes - a.likes).slice(0, 9)
  return //...
}
複製代碼

組件每次re-render時,topTen變量都會是一個全新的引用值,哪怕posts變量值沒有發生改變或者slice的結果也沒有發生變化。但這仍然會對文章列表產生沒有必要的re-render

你能夠緩存你獲取的數據來解決這個問題。好比,把獲取數據操做放入state中,而且僅在posts屬性發生更新時更新。

componentWillMount() {
  this.setTopTenPosts(this.props.posts)
}
componentWillReceiveProps(nextProps) {
  if (this.props.posts !== nextProps.posts) {
    this.setTopTenPosts(nextProps)
  }
}
setTopTenPosts(posts) {
  this.setState({
    topTen: posts.sort((a, b) => b.likes - a.likes).slice(0, 9)
  })
}
複製代碼

若是你使用Redux,考慮使用reselect來建立選擇器去組合而且緩存你獲取的數據。

最後

只要你明確如下兩點,相比於Component,使用PureComponent就很安全:

  • 改變數據一般是很差的,尤爲是使用PureComponent時會讓問題更復雜

  • 若是你在render方法中建立了新函數對象數組,那麼你的作法是錯的

感謝Daniel Min將這篇文章翻譯至Korean

相關文章
相關標籤/搜索