tldr;優先使用
PureComponent
,而且永遠不要改變數據對象(或者使用其它最佳實踐)github
我使用PureComponent
已經有一段時間,這基於它是一個更具性能的組件版本。redux
事實證實這是真的,可是性能優點帶來了一些必要前提。數組
咱們來深刻研究PureComponent
而且理解爲何咱們應該去使用它。緩存
Component
個PureComponent
只有一個區別PureComponent
和Component
幾乎徹底同樣,惟一的區別是PureComponent
爲你處理shouldComponentUpdate
事件。安全
當props
或state
發生變化,PureComponent
會對二者都作淺比較
;而Component
則不會對二者的新舊值進行比較。因此,不管什麼時候調用shouldComponentUpdate
,組件都會默認觸發re-render
。async
譯者注:
shouldComponentUpdate
默認返回true
,必定觸發re-render
函數
當對props
和state
的新舊值進行比較時,淺比較
只會檢查基本數據類型
的值是否相等(好比:1
等於1
或者true
等於true
),複雜如對象
和數組
也是如此,不過是去比較引用值
。工具
你可能聽過,不要對props
和state
中的對象
和數組
進行改變。若是你在父組件對對象
進行了改變,你的純
子組件並不會更新。儘管上游的值發生了改變,可是子組件只會對props
進行引用值
的比較而且沒法檢測到區別。post
譯者注:這裏改變,指
不改變
對象引用的操做
而正確的作法是,藉助ES6
的object
新特性、array
的擴展運算符
或者使用不可變工具庫
來返回新對象
。
譯者注:這裏改變,指
改變
對象引用的操做
對基本數據類型
的值和引用數據類型
的引用值
比較是個極其廉價的操做。若是你有一組子組件列表而且其中一個更新了,相比於從新渲染全部,在每個子組件上進行props
和state
的比較仍然是一個很是快的過程。
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