React PureComponent介紹與使用

前言

介紹之前可以先看下shouldComponentUpdate介紹

PureComponent介紹

React15.3中新加了一個 PureComponent 類,顧名思義, pure 是純的意思, PureComponent 也就是純組件,取代其前身 PureRenderMixin , PureComponent 是優化 React 應用程序最重要的方法之一,易於實施,只要把繼承類從 Component 換成 PureComponent 即可,可以減少不必要的 render 操作的次數,從而提高性能,而且可以少寫 shouldComponentUpdate 函數(shouldComponentUpdate通過判斷props和state是否發生變化來決定需不需要重新渲染組件),主要目的就是防止不必要的子組件渲染更新。

PureComponent原理

當組件更新時,如果組件的 props 和 state 都沒發生改變, render 方法就不會觸發,省去 Virtual DOM 的生成和比對過程,達到提升性能的目的。具體就是 React 自動幫我們做了一層淺比較:

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

而 shallowEqual 又做了什麼呢?會比較 Object.keys(state | props) 的長度是否一致,每一個 key 是否兩者都有,並且是否是一個引用。

簡單用代碼實現:

/*
 * React.PureComponent
 */
// 把兩個對象進行淺比較
// 只比較對象的第一級
// 如果屬性值是基本類型的,我們只需要比較值是否一樣即可
function shallowEqual(obj1, obj2) {
	if (Object.keys(obj1).length !== Object.keys(obj2).length){
		return false;
	}
	for (let key in obj1) {
		if (obj1[key] !== obj2[key]) {
			return false;
		}
	}
	return true;
}

源碼:

// 淺比較shallowEqual的源碼
const hasOwn = Object.prototype.hasOwnProperty
// 這個函數實際上是Object.is()的polyfill
function is(x, y) {
  if (x === y) {
    return x !== 0 || y !== 0 || 1 / x === 1 / y
  } else {
    return x !== x && y !== y
  }
}

export default function shallowEqual(objA, objB) {
    // 首先對基本數據類型的比較
  if (is(objA, objB)) return true
 // 由於Obejct.is()可以對基本數據類型做一個精確的比較, 所以如果不等
  // 只有一種情況是誤判的,那就是object,所以在判斷兩個對象都不是object之後,就可以返回false了
  if (typeof objA !== 'object' || objA === null ||
      typeof objB !== 'object' || objB === null) {
    return false
  }
// 過濾掉基本數據類型之後,就是對對象的比較了
  // 首先拿出key值,對key的長度進行對比
  const keysA = Object.keys(objA)
  const keysB = Object.keys(objB)
// 長度不等直接返回false
  if (keysA.length !== keysB.length) return false
  for (let i = 0; i < keysA.length; i++) {
  // key值相等的時候
  // 借用原型鏈上真正的 hasOwnProperty 方法,判斷ObjB裏面是否有A的key的key值
  // 屬性的順序不影響結果也就是{name:'daisy', age:'24'} 跟{age:'24',name:'daisy' }是一樣的
  // 最後,對對象的value進行一個基本數據類型的比較,返回結果
    if (!hasOwn.call(objB, keysA[i]) ||
        !is(objA[keysA[i]], objB[keysA[i]])) {
      return false
    }
  }

  return true
}

淺比較就是隻比較第一級,對於基本數據類型,只比較值;對於引用數據類型值,直接比較地址是否相同,不管裏面內容變不變,只要地址一樣,我們就認爲沒變。所以在這種情況下,我們以後用的時候,對於引用類型值修改狀態或修改屬性時候,對於它賦值的時候,我們儘可能把之前值拿過來克隆一份,賦給它新的地址就好~這是我們的注意點!我們想做性能優化的時候就可以在Component裏做一個淺比較。

總結下就是React.PureComponent是基於淺比較,所以只要屬性值是引用類型,但是修改後的值變了,但是地址不變,也不會重新渲染。在深層數據結構發生變化時可以調用 forceUpdate() 來確保組件被正確地更新。也可以用 immutable 對象加速嵌套數據的比較。

PureComponent使用(在class組件使用)

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

class Title extends PureComponent {
    render() {
        console.log("我是title組件")
        return (
            <div>
                標題:{this.props.title}
            </div>
        )
    }
}


class Count extends Component {
    render() {
        console.log("我是條數組件")
        return (
            <div>
                條數:{this.props.count}
            </div>
        )
    }
}

export default class Purememo extends Component {
    constructor(props){
        super(props)
        this.state={
            title:'shouldComponentUpdate使用',
            count:0
        }
    }
    componentDidMount(){
        setInterval(()=>{
            this.setState({
                count:this.state.count+1
            })
        },1000)
    }
    render() {
        return (
            <div>
                <Title title={this.state.title}></Title>
                <Count count={this.state.count}></Count>
            </div>
        )
    }
}

PureComponent與shouldComponentUpdate 共存

經過上面的簡單介紹,其實可以知道如果 PureComponent 裏有 shouldComponentUpdate 函數的話,直接使用 shouldComponentUpdate 的結果作爲是否更新的依據,沒有 shouldComponentUpdate 函數的話,纔會去判斷是不是 PureComponent ,是的話再去做 shallowEqual 淺比較。

// 這個變量用來控制組件是否需要更新
var shouldUpdate = true;
// inst 是組件實例
if (inst.shouldComponentUpdate) {
  shouldUpdate = inst.shouldComponentUpdate(nextProps, nextState, nextContext);
} else {
  if (this._compositeType === CompositeType.PureClass) {
    shouldUpdate = !shallowEqual(prevProps, nextProps) ||
      !shallowEqual(inst.state, nextState);
  }
}

與老版本共存

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

class App extends (PureComponent || Component) {
  //...
}

注:PureComponent不可濫用,他使用在class組件內,只有那些狀態和屬性不經常的更新的組件我們用來做優化,對於經常更新的,這樣處理後反而浪費性能,因爲每一次淺比較也是要消耗時間的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章