React性能優化方案之PureComponent

PureComponent介紹react

以前的一篇文章React性能優化方案之PureRenderMixin,是對react的shouldComponentUpdate的方法進行重寫去優化。但自從React15.3中新加了一個 PureComponent 類,易於在本身的組件使用,只須要將Component 換成 PureComponent 便可,因此原做者建議使用今天要介紹的PureComponent。數組

PureComponent原理性能優化

咱們知道組件的state和props的改變就會觸發render,可是組件的state和props沒發生改變,render就不執行,只有PureComponent檢測到state或者props發生變化時,PureComponent纔會調用render方法,所以,你不用手動寫額外的檢查,就能夠達到提升性能的而目的。實際上react作了最外層的淺比較:bash

if (this._compositeType === CompositeTypes.PureClass) {
  shouldUpdate = !shallowEqual(prevProps, nextProps) || ! shallowEqual(inst.state, nextState);
}
複製代碼

shadowEqual只會淺檢查組件的props和state,因此嵌套對象和數組是不會被比較的。深比較是要逐層遍歷枚舉對應的鍵值進行比對,這個操做比較浪費時間。若是比較的深的狀況,你也可使用shouldComponentUpdate來手動單個比較是否須要從新渲染。最簡單的方式就是直接比較props或state:函數

shouldComponentUpdate(nextProps, nextState) {
  return nextProps.xxx.xx === props.xxx.xx;
}
複製代碼

另外,你可使用immutable屬性,Immutable.js就是一個Immutable庫。這種狀況下,屬性的比較是很是容易的,由於已存在的對象就不會發生改變,取而代之的是從新建立新的對象。post

使用PureComponent性能

爬坑1:易變數據不能使用一個引用優化

PureComponent節約了咱們的時間,避免了多餘的代碼。那麼,掌握如何正確使用它是很是重要的,不然若是使用不當,它就沒法發揮做用。例如,讓咱們想一想這樣一種狀況,父組件有一個render方法和一個click處理方法:ui

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是一個純組件,這時候點擊它是不會被渲染的,可是咱們的確向this.state.items加入了新的值,可是它仍然指向同一個對象的引用。可是,經過移除可變對象就很容易改變這種狀況,使之可以正確被渲染。this

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

爬坑2:不變數據使用一個引用

上面易變數據不能使用一個引用的案例中有一個點擊刪除操做,若是咱們刪除的代碼這麼寫:

constructor(props){
    super(props)
    this.state={
        items: [{a: 1}, {a: 2}, {a: 3}]
    }
}
handleClick = () => {
  const { items } = this.state;
  items.splice(items.length - 1, 1);
  this.setState({ items });
}
複製代碼

items 的引用也是改變的,但若是 items 裏面是引用類型數據這時候state.items[0] === nextState.items[0]是false,子組件裏仍是從新渲染了。這樣就須要咱們保證不變的子組件數據的引用不能改變。這個時候可使用前面說的immutable-js函數庫。

爬坑3:父給子經過props傳遞迴調函數

咱們在子父通訊傳遞迴調函數時候:

// step1
<MyInput onChange={e => this.props.update(e.target.value)} />
// step2
update(e) {
  this.props.update(e.target.value)
}
render() {
  return <MyInput onChange={this.update.bind(this)} />
}

複製代碼

因爲每次 render 操做 MyInput 組件的 onChange 屬性都會返回一個新的函數,因爲引用不同,因此父組件的 render 也會致使 MyInput 組件的 render ,即便沒有任何改動,因此須要儘可能避免這樣的寫法,最好封裝:

update = (e) => {
  this.props.update(e.target.value)
}
render() {
  return <MyInput onChange={this.update} />
}
複製代碼

爬坑4:新數組,空數組,也會致使組件從新渲染

<Entity values={this.props.values || []}/>
複製代碼

爲了不這個問題,你可使用defaultProps,它包含了一個屬性的初始化空狀態。在純組件(PureComponent)被建立時,由於函數的新對象被建立了,因此它會得到新數據,而且從新渲染。解決這個問題最簡單的方法就是: 在組件的constructor方法中使用bind。

constructor(props) {
    super(props)
    this.update = this.update.bind(this)
}
update(e) {
    this.props.update(e.target.value)
}
render() {
    return <MyInput onChange={this.update} />
}
複製代碼

同時,在JSX中,任何包含子元素(child elements)的組件,shallowEqual檢查總會返回false。

PureComponent使用方式

用法很簡單:

import React { PureComponent, Component } from 'react';

class Foo extends (PureComponent || Component) {
  //...
}
複製代碼

老版本兼容寫法,在老版本的 React 裏也不會報錯的。

總結

1.純組件忽略從新渲染時,不只會影響它自己,並且會影響它的說有子元素,因此,使用PureComponent的最佳狀況就是展現組件,它既沒有子組件,也沒有依賴應用的全局狀態

2.PureComponent 真正起做用的,只是在一些純展現組件上,複雜組件用了也不要緊,反正 shallowEqual 那一關就過不了,不過記得 props 和 state 不能使用同一個引用。

相關文章
相關標籤/搜索