react如何性能達到最大化(前傳),暨react爲啥非得使用immutable.js

一行代碼賽過千言萬語。。這篇文章呢。。主要講述我一步一步優化react性能的過程。。爲啥要用immutable.js呢。絕不誇張的說。有了immutable.js(固然也有其餘實現庫)。。才能將react的性能發揮到極致!要是各位看官用過一段時間的react,而沒有用immutable那麼本文很是適合你。那麼我開始吧!react

1,對於react的來講,若是父組件有多個子組件

想象一下這種場景,一個父組件下面一大堆子組件。而後呢,這個父組件re-render。是否是下面的子組件都得跟着re-render。但是不少子組件裏面是冤枉的啊!!不少子組件的props 和 state 然而並無改變啊!!雖然virtual dom 的diff 算法很快。。可是性能也不是這麼浪費的啊!!下面咱們上代碼算法

1.原始代碼以下

如下是父組件代碼。。負責輸入name 和 age 而後循環顯示name 和 ageredux

export default class  extends Component {
      constructor(props){
        super(props)
        this.state={
          name:"",
          age :"",
          persons:[]
        }
      }
      render() {
        const {name,age,persons} = this.state
        return (
          <div>
            <span>姓名:</span><input value={name} name="name" onChange={this._handleChange.bind(this)}></input>
            <span>年齡:</span><input value={age} name="age" onChange={this._handleChange.bind(this)}></input>
            <input type="button" onClick={this._handleClick.bind(this)} value="確認"></input>
            {persons.map((person,index)=>(
              <Person key={index} name={person.name} age={person.age}></Person>
            ))}
          </div>
        )
      }
      _handleChange(event){
        this.setState({[event.target.name]:event.target.value})
      }
      _handleClick(){
        const {name,age} = this.state
        this.setState({
          name:"",
          age :"",
          persons:this.state.persons.concat([{name:name,age:age}])
        })
    
      }
    }

如下是子組件代碼單純的顯示name和age而已安全

class Person  extends Component {
  componentWillReceiveProps(newProps){
    console.log(`我新的props的name是${newProps.name},age是${newProps.age}。我之前的props的name是${this.props.name},age是${this.props.age}是我要re-render了`);
  }
  render() {
    const {name,age} = this.props;

      return (
        <div>
          <span>姓名:</span>
          <span>{name}</span>
          <span> age:</span>
          <span>{age}</span>
        </div>
      )
  }
}

運行起來長下圖這個樣
圖片描述
好那麼問題來了。。咱們看一下控制檯
圖片描述
天哪,,這麼屢次re-reder..細細觀看。。不難發現。要re-render這麼屢次。。父組件一re-render,子組件就跟着re-render啊。。那麼多麼浪費性能,好。。PureRenderMixin出場dom

2,PureRenderMixin

由於咱用的是es2015的 Component,因此已經不支持mixin了。。不過不要緊,能夠用
HOCs,這個比mixin還更受推崇呢。。我有空回用代碼來展現他倆的異同,鑑於不是本文重點,,你們能夠看這兩篇文章瞭解下React Mixin 的前世此生Mixins Are Dead. Long Live Composition
因此在這裏咱們用Pure render decorator代替PureRenderMixin,那麼代碼以下函數

import pureRender from "pure-render-decorator"
...

@pureRender
class Person  extends Component {
  render() {
    console.log("我re-render了");
    const {name,age} = this.props;

      return (
        <div>
          <span>姓名:</span>
          <span>{name}</span>
          <span> age:</span>
          <span>{age}</span>
        </div>
      )
  }
}

加個這東西就完事了??看上去咋這麼不使人信服啊。。無論怎樣。。試試吧
圖片描述
果真能夠作到pure render。。在必須render 的時候才render
好咱們看看它的神奇之處性能

@pureRender

是es7的Decorators語法。上面這麼寫就和下面這麼寫同樣優化

class PersonOrigin  extends Component {
  render() {
    console.log("我re-render了");
    const {name,age} = this.props;

      return (
        <div>
          <span>姓名:</span>
          <span>{name}</span>
          <span> age:</span>
          <span>{age}</span>
        </div>
      )
  }
}
const Person = pureRender(PersonOrigin)

pureRender其實就是一個函數,接受一個Component。把這個Component搞一搞,返回一個Component
看他pureRender的源代碼就一目瞭然this

function shouldComponentUpdate(nextProps, nextState) {
  return shallowCompare(this, nextProps, nextState);
}

function pureRende(component) {
  component.prototype.shouldComponentUpdate = shouldComponentUpdate;
}
module.exports = pureRender;

pureRender很簡單,就是把傳進來的component的shouldComponentUpdate給重寫掉了,原來的shouldComponentUpdate,不管怎樣都是return ture,如今不了,我要用shallowCompare比一比,shallowCompare代碼及其簡單,以下spa

function shallowCompare(instance, nextProps, nextState) {
  return !shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState);
}

一目瞭然。分別拿如今props&state和要傳進來的props&state,用shallowEqual比一比,要是props&state都同樣的話,就return false,是否是感受很完美?不。。這纔剛剛開始,問題就出在shallowEqual上了

3,shallowEqual的問題

shallowEqual引發的bug

不少時候,父組件向子組件傳props的時候,可能會傳一個複雜類型,好比咱們改下。

render() {
    const {name,age,persons} = this.state
    return (
      <div>
...省略.....
        {persons.map((person,index)=>(
          <Person key={index} detail={person}></Person>
        ))}
      </div>
    )
  }

person是一個複雜類型。。這就埋下了隱患,,在演示隱患前,咱們先說說shallowEqual,是個什麼東西,shallowEqual其實只比較props的第一層子屬性是否是相同,就像上述代碼,props 是以下

{
    detail:{
       name:"123",
       age:"123"}
}

他只會比較props.detail ===nextProps.detail
那麼問題來了,上代碼
若是我想修改detail的時候考慮兩種狀況

狀況一,我修改detail的內容,而不改detail的引用

這樣就會引發一個bug,好比我修改detail.name,由於detail的引用沒有改,因此
props.detail ===nextProps.detail 仍是爲true。。
因此咱們爲了安全起見必須修改detail的引用,(redux的reducer就是這麼作的)

狀況二,我修改detail的引用

這種雖然沒有bug,可是容易誤殺,好比若是我新舊兩個detail的內容是同樣的,豈不是還要,render。。因此仍是不完美,,你可能會說用 深比較就行了,,可是 深比較及其消耗性能,要用遞歸保證每一個子元素同樣,

這只是說沒有用immutable引發各類?。。下一篇我講寫,,如何用immutable.js..

相關文章
相關標籤/搜索