以下 react 源码版本为 18.3.0
浅比较:用于判断“props 是否变了”,以便直接跳过组件渲染。
源码位置 18:50:packages/shared/shallowEqual.js
import is from './objectIs';
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++) {
const k = keysA[i];
if (!hasOwnProperty.call(objB, k) || !is(objA[k], objB[k])) {
return false;
}
}
return true;
}
源码位置 packages/shared/objectIs.js
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
);
}
const objectIs: (x: any, y: any) => boolean = typeof Object.is === 'function' ? Object.is : is;
export default objectIs;
(x !== 0 || 1 / x === 1 / y) 这段逻辑是在区分 +0 和 -0:
x === y先判断“严格相等”。在 JS 里+0 === -0为 true。(x !== 0 || 1 / x === 1 / y)用来过滤掉 0 的特殊情况:- 如果
x不是 0,直接通过。 - 如果
x是 0,就比较1/x和1/y:1/+0得到+Infinity,1/-0得到-Infinity。只有两者都为同号时才算相等,从而把 +0 和 -0 区分开。
- 如果
在 React.memo 组件路径中,默认比较器是 shallowEqual;若比较为真且 ref 未变,则直接 bailout,不再渲染子树
549:555:packages/react-reconciler/src/ReactFiberBeginWork.new.js
const prevProps = currentChild.memoizedProps;
// Default to shallow comparison
let compare = Component.compare;
compare = compare !== null ? compare : shallowEqual;
if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
总结:
- 浅比较:检查 props(和 ref)是否变化,若无变化可直接 bail out,避免组件及其子树重渲。