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

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

提问人:Shelly Hsueh 提问时间:10/3/2019 更新时间:10/4/2019 访问量:13583

问:

我正在研究 React-Redux-v.7.1 提供的 Hooks API 是如何工作的,并在 Equality Comparisons and Updateshttps://react-redux.js.org/api/hooks#equality-comparisons-and-updates) 中看到它提到:

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

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

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

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

而 react-redux/src/connect/connect.js 中的相等性检查是使用 Object.is() 和其他检查,这与 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
}

根据 MDN 中对 Object.is() 的描述:“Object.is 不进行类型转换,也不对 NaN、-0 和 +0 进行特殊处理(除了那些特殊的数值外,它的行为与 === 相同)。"

我不知道为什么 a === b 比一系列相等性检查更好。 (这是我第一次在这里提问,为粗鲁或缺乏信息道歉)

javascript reactjs react-redux 比较 相等

评论


答:

31赞 azundo 10/3/2019 #1

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

import {connect} from 'react-redux';

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

每当存储以任何方式更改时,都会调用 here,因此返回值将始终是新对象,即使 并且不会更改。因此,使用浅层比较来决定是否需要重新渲染。mapStateToPropskeyAkeyB

对于钩子情况:

import {useSelector} from 'react-redux';

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

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

如果您只想使用返回复合对象的单个钩子,则您链接到的文档具有使用相等函数的示例: https://react-redux.js.org/api/hooks#equality-comparisons-and-updatesuseSelectorshallowEqual

评论

0赞 Shelly Hsueh 10/3/2019
谢谢,我很清楚!因此,重要的不是哪个更好,而是取决于它们的工作方式。再次感谢您的快速回答和清晰的例子:D
0赞 azundo 10/4/2019
谢谢!不确定我是否仅用文字就非常清楚地表达了我的观点——我很高兴这些例子有所帮助。