提问人:Shelly Hsueh 提问时间:10/3/2019 更新时间:10/4/2019 访问量:13583
React-Redux 中的严格相等 (===) 与浅相等检查
Strict Equality (===) versus Shallow Equality Checks in React-Redux
问:
我正在研究 React-Redux-v.7.1 提供的 Hooks API 是如何工作的,并在 Equality Comparisons and Updates (https://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 比一系列相等性检查更好。 (这是我第一次在这里提问,为粗鲁或缺乏信息道歉)
答:
使用 ,返回从存储中选择的所有状态的复合对象,因此对其键进行浅层比较是有意义的。使用 ,的模式通常是每次调用 时只返回一个值,类似于钩子只处理单个值而不是所有状态值的方式。因此,如果每次调用都直接返回一个值,那么严格的相等性检查与浅层比较是有意义的。一个简短的例子应该更清楚地说明这一点。connect
mapStateToProps
useSelector
useSelector
useState
useSelector
import {connect} from 'react-redux';
const mapStateToProps = state => (
{keyA: state.reducerA.keyA, keyB: state.reducerB.keyB}
);
export default connect(mapStateToProps)(MyComponent);
每当存储以任何方式更改时,都会调用 here,因此返回值将始终是新对象,即使 并且不会更改。因此,使用浅层比较来决定是否需要重新渲染。mapStateToProps
keyA
keyB
对于钩子情况:
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-updatesuseSelector
shallowEqual
评论