Component或PureComponent
PureComponent,前身是 PureRenderMixin ,和 Component 基本一樣,只不過會在 render 之前幫組件自動執行一次shallowEqual(淺比較),來決定是否更新組件,淺比較類似於淺複製,只會比較第一層
Component只要setState()和props的改變就會觸發render
而我們不想頁面重新render就得自己寫shouldComponentUpdate來攔截render
shouldComponentUpdate(nextProps, nextState) {
return nextProps.xxx.xx === props.xxx.xx;
}
PureComponent
PureComponent爲你處理shouldComponentUpdate事件。
當props或state發生變化,PureComponent會對兩者都做淺比較;
而Component則不會對兩者的新舊值進行比較。
if (this._compositeType === CompositeTypes.PureClass) {
shouldUpdate = !shallowEqual(prevProps, nextProps)
|| !shallowEqual(inst.state, nextState);
}
淺比較
淺比較只會檢查基本數據類型的值是否相等(比如:1等於1或者true等於true),複雜如對象和數組只是比較引用值
並且只會去比較第一層的,不會遞歸去比較,那樣render會更復雜
注意問題
易變數據不能使用一個引用
會發現,無論怎麼點 delete 按鈕, li 都不會變少,因爲 items 用的是一個引用, shallowEqual 的結果爲 true 。
這裏的items其實都是指向state中的items來操作的,本質上引用並沒有改變,不會觸發render
class App extends PureComponent {
state = {
items: [1, 2, 3]
}
handleClick = () => {
const { items } = this.state;
items.pop();
this.setState({ items });
}
render() {
return (<div>
<ul>
{this.state.items.map(i => <li key={i}>{i}</li>)}
</ul>
<button onClick={this.handleClick}>delete</button>
</div>)
}
}
想要觸發render得讓引用改變
handleClick = () => {
const { items } = this.state;
items.pop();
this.setState({ items: [].concat(items) });
}
父組件向子組件傳遞函數
父組件裏面有一組子組件列表,每一個都傳給父組件方法一個唯一的參數。爲了綁定這個參數,你可能這樣做:
<CommentItem likeComment={() => this.likeComment(user.id)} />
問題是每一次父組件的render方法調用時,() => this.likeComment(user.id)都會執行返回一個新函數(伴隨着新的引用)就會被創建並且傳遞給likeComment屬性。
這樣子組件的props的淺比較時就會發現props引用變了導致render
所以我們要這樣寫可以減少render
<CommentItem likeComment={this.likeComment} userID={user.id} />
在render方法中獲取數據需要特別注意
下面這段代碼中父組件每次render topTen的引用都會重新生成(變了)就會導致子組件用了這個變量的render
render() {
const { posts } = this.props
const topTen = posts.sort((a, b) => b.likes - a.likes).slice(0, 9)
return //...
}