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 比一系列相等性检查更好。
(第一次在这里提问,如有冒犯或信息不足请见谅)
与 connect
、mapStateToProps
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 值将始终是一个新对象,即使 keyA
和 keyB
不要换。因此使用浅比较来决定是否需要重新渲染。
对于 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
我正在研究 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 比一系列相等性检查更好。 (第一次在这里提问,如有冒犯或信息不足请见谅)
与 connect
、mapStateToProps
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 值将始终是一个新对象,即使 keyA
和 keyB
不要换。因此使用浅比较来决定是否需要重新渲染。
对于 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