天天看點

React源碼解析之PureComponet的淺比較

前言:

在 React源碼解析之updateClassComponent(下) 中提到了

PureComponent

的淺比較:

//如果是純元件的話,用**淺比較**來比較 props/state
  if (ctor.prototype && ctor.prototype.isPureReactComponent) {
    return (
      //淺等于的判斷
      !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
    );
  }
           

複制

接下來就看下

shallowEqual()

的源碼

一、shallowEqual

作用:

PureComponet

做淺比較的核心

function

源碼:

import is from './objectIs';

const hasOwnProperty = Object.prototype.hasOwnProperty;

/**
 * Performs equality by iterating through keys on an object and returning false
 * when any key has values which are not strictly equal between the arguments.
 * Returns true when the values of all keys are strictly equal.
 */
//true 為不要更新
//false 為要更新
function shallowEqual(objA: mixed, objB: mixed): boolean {
  //同 Object.js()
  //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Description
  //不要更新
  if (is(objA, objB)) {
    return true;
  }
  //隻要有一個不是 object或為 null 則傳回 false,要更新
  if (
    typeof objA !== 'object' ||
    objA === null ||
    typeof objB !== 'object' ||
    objB === null
  ) {
    return false;
  }

  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB);
  //兩個 object 的key 數不一樣,則傳回 false,要更新
  if (keysA.length !== keysB.length) {
    return false;
  }

  // Test for A's keys different from B.
  //每一個 value 去一一比較是否是淺相等
  //能執行到這裡,說明兩者 key 的長度是相等的
  for (let i = 0; i < keysA.length; i++) {
    if (
      //不通過原型鍊查找是否有自己的屬性
      !hasOwnProperty.call(objB, keysA[i]) ||
      //判斷兩值是否相等
      !is(objA[keysA[i]], objB[keysA[i]])
    ) {
      //隻要沒有屬性/兩個value不等,則傳回 false,需要更新
      return false;
    }
  }
  //預設傳回 true,不需要更新
  return true;
}

export default shallowEqual;
           

複制

解析:

(1) 關于

PureComponet

Component

的差別,請看:

https://zh-hans.reactjs.org/docs/react-api.html#reactpurecomponent

(2)

is()

Object.is()

,React 直接将其 實作在代碼内部了:

/**
 * inlined Object.is polyfill to avoid requiring consumers ship their own
 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
 */
function is(x: any, y: any) {
  return (
    (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare
  );
}

export default is;
           

複制

關于

Object.is()

的作用及用法,請看:

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/is

(3) 注意下傳回的

true/false

因為是 return

!shallowEqual()

,是以

true

表示不更新,

false

表示要更新

(4) 主要分四種情況

① 非對象類型的比較,直接使用

is(objA, objB)

判斷

② 到 ④ 是對象類型的比較 :

objA/objB

中,隻要有一個不是

object

或為

null

則傳回

false

objA/objB

keyLength

不一樣,則傳回

false

,此舉的目的是簡單比較,優化性能

④ 循環比較

objA/objB

的每一個

value

,判斷是否淺相等

針對 ④ 的例子:

對象的

value

是非對象類型:

const a={c:1,d:2}
const b={c:1,d:2}

Object.is(a,b) //false

hasOwnProperty.call(b, 'c') //true

Object.is(a['c'], b['c']) //true
           

複制

對象的

value

是對象類型:

const a={c:{e:3},d:2}
  const b={c:{e:3},d:2}

  hasOwnProperty.call(b, 'c') //true
  //可以看到,隻能用于淺比較
  Object.is(a['c'], b['c']) //false
           

複制

可以看到,

Object.is()

PureComponet

做淺比較的根本函數。

GitHub:

https://github.com/AttackXiaoJinJin/reactExplain/blob/master/react16.8.6/packages/shared/shallowEqual.js

(完)