React中的Component 和 PureComponent

React.ComponentReact.PureComponent很類似,兩則的區別在於,PureComponent類幫咱們以淺比較的方式對比propsstate,實現了shouldComponentUpdate()函數,在某些狀況下,使用PureComponent能夠減小render函數的執行,提高性能。react

PureComponent可以提高性能

當Index組件繼承Component算法

  1. 初次渲染時控制檯會依次打印"constructor"、"render";bash

  2. 當第一次點擊按鈕更新state時,控制檯會依次打印"render"、"componentDidUpdate";函數

  3. 後續每次觸發點擊事件,儘管flag的值沒有變化,控制檯仍是會依次打印"render"、"componentDidUpdate",說明組件依然調用render()componentDidUpdate()函數,顯然這是多餘的,一般咱們會手動從新實現shouldComponentUpdate(nextProps, nextState)函數判斷stateprops的狀態再來決定是否須要從新渲染性能

import React from 'react';

class Index extends React.PureComponent{
  constructor(props) {
    super(props);
    this.state = {
      flag:false
    };
    console.log('constructor');
  }
  changeState = () => {
    this.setState({
      flag: true
    })
  };
  render() {
    console.log('render');
    return (
      <div>
        <button onClick={this.changeState}>Click me</button>
        <div>
         {this.state.flag.toString()}
        </div>
      </div>
    );
  }
  componentDidUpdate() {
    console.log("componentDidUpdate")
  }
}

export default Index;
複製代碼

當Index組件繼承PureComponentui

  • 初次渲染和第一次點擊按鈕更新state時控制檯輸出同上面繼承Component同樣沒有變化this

  • 後續每次觸發點擊事件,控制檯無輸出, 省去執行render函數生成虛擬DOM,進行DIFF算法比較等後續操做spa

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

PureComponent默認實現的shouldComponentUpdate()方法使用的是淺比較: 即值的比較或引用的比較, 不會進行深層次的對比,因此當propsstate的值是引用類型時,即便對象的值改變了,可是對象的引用沒變code

import React from 'react';

class IndexPage extends React.PureComponent{
  constructor(props) {
    super(props);
    this.state = {
      arr: [1,2,3,4,5]
    };
  }
  changeArr = () => {
    let {arr} = this.state
    arr.pop()
    this.setState({
      arr
    })
    console.log("changeArr", arr)
  };
  render() {
    const { arr } = this.state
    console.log('render', arr);
    return (
      <div>
        <button onClick={this.changeArr}>pop</button>
        <ul>
        {
          arr.map(item => <li key={item}>{item}</li>)
        }
        </ul>
      </div>
    );
  }
  componentDidUpdate() {
    console.log("componentDidUpdate")
  }
}

export default IndexPage;
複製代碼
  1. 初次渲染時控制檯會打印 render (5) [1, 2, 3, 4, 5]
  2. 當點擊pop按鈕時控制檯會依次打印 changeArr (4) [1, 2, 3, 4]changeArr (4) [1, 2, 3] ...... 可是render函數不執行, 由於PureComponent實現的shouldComponentUpdate()認爲值的引用沒有變,故不執行後續的操做,只有在引用改變的狀況下函數纔會返回true

PureComponent也會影響子組件

下面例子中的render函數只會在剛建立的時候執行一次, 後續的點擊按鈕操做,因爲PureComponent中的ShouldComponentUpdate()執行淺比較(對象值的引用沒變),不會觸發render函數的執行,其子組件也不會更新。component

import React from 'react';
import Item from './Item'

class IndexPage extends React.PureComponent{
  constructor(props) {
    super(props);
    this.state = {
      arr: [1,2,3,4,5]
    };
  }
  changeArr = () => {
    let {arr} = this.state
    arr.pop()
    this.setState({
      arr
    })
    console.log("changeArr", arr)
  };
  render() {
    const { arr } = this.state
    console.log('render', arr);
    return (
      <div>
        <button onClick={this.changeArr}>pop</button>
        <ul>
          <Item arr={arr} />
        </ul>
      </div>
    );
  }
  componentDidUpdate() {
    console.log("componentDidUpdate")
  }
}

export default IndexPage;
複製代碼
// Item.js
import React, { Fragment, Component } from 'react'

class Index extends Component {
  render() {
    const { arr } = this.props;
    console.log("children", arr)
    return (
      <Fragment>
        {
          arr.map(item => <li key={item}>{item}</li>)
        }
      </Fragment>
    )
  }
}

export default Index;
複製代碼

總結

  1. PureComponent已經用淺層對比propsstate的方式替咱們實現了shouldComponentUpdate(), 不只能影響自身,還會影響其子組件;
  2. PureComponent 某些狀況下(propsstate的值不常常變更, 由於淺比較也會耗時)能夠提高性能;
  3. 繼承自Component中的組件shouldComponentUpdate()默認狀況下老是返回true;
相關文章
相關標籤/搜索