React-Redux 中的严格相等(===)与浅层相等检查

Strict Equality (===) versus Shallow Equality Checks in React-Redux

我正在研究 React-Redux-v.7.1 提供的 Hooks API 是如何工作的,并且在 Equality Comparisons and Updates[=44] 中看到了它=] (https://react-redux.js.org/api/hooks#equality-comparisons-and-updates) 即:

"从 v7.1.0-alpha.5 开始,默认比较是严格的 === 引用比较。这不同于 connect(),它对 mapState 调用的结果使用浅层相等性检查来确定是否需要重新渲染。这对您应该如何使用有几个影响useSelector()."

我想知道 为什么严格相等比 connect() 使用的浅相等要好?然后我研究了他们的平等比较:

useSelector() 的默认严格相等性检查只是检查 a===b

const refEquality = (a, b) => a === b

并在 react-redux/src/connect/connect.js is using Object.is() and also other checks, which is same as that in react 中检查相等性。

// The polyfill of Object.is()
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

  if (
    typeof objA !== 'object' ||
    objA === null ||
    typeof objB !== 'object' ||
    objB === null
  ) {
    return false
  }

  const keysA = Object.keys(objA)
  const keysB = Object.keys(objB)

  if (keysA.length !== keysB.length) return false

  for (let i = 0; i < keysA.length; i++) {
    if (!hasOwn.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
      return false
    }
  }

  return true
}

根据 the description of Object.is() in MDN: "Object.is 没有类型转换,也没有对 NaN、-0 和 +0 进行特殊处理(给它 与 === 相同的行为,除了那些特殊数值 )。"

我不知道为什么 a === b 比一系列相等性检查更好。 (第一次在这里提问,如有冒犯或信息不足请见谅)

connectmapStateToProps return 是从存储中选择的所有状态的复合对象,因此对其键进行浅层比较是有意义的。对于 useSelector,模式通常是 return 每次调用 useSelector 的单个值,类似于 useState 钩子只处理单个值而不是所有的状态值。因此,如果每次直接调用 useSelector returns 一个值,那么严格的相等性检查与浅比较是有意义的。一个简短的例子应该可以更清楚地说明这一点。

import {connect} from 'react-redux';

const mapStateToProps = state => (
  {keyA: state.reducerA.keyA, keyB: state.reducerB.keyB}
);
export default connect(mapStateToProps)(MyComponent);

此处 mapStateToProps 每次存储以任何方式更改时都会被调用,因此 return 值将始终是一个新对象,即使 keyAkeyB不要换。因此使用浅比较来决定是否需要重新渲染。

对于 hooks 案例:

import {useSelector} from 'react-redux';

function MyComponent(props) {
  const keyA = useSelector(state => state.reducerA.keyA);
  const keyB = useSelector(sate => state.reducerB.keyB);
  ...
}

现在 useSelector 挂钩的结果是存储中的单个值,而不是复合对象。所以在这里使用严格相等作为默认值是有道理的。

如果您只想使用一个 useSelector 钩子 return 是一个复合对象,您链接到的文档有一个使用 shallowEqual 相等函数的示例:https://react-redux.js.org/api/hooks#equality-comparisons-and-updates