Component或PureComponent

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 //...
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章