React浅比较问题
React
的浅比较在React
中无处不在,比如Context
中的value
、React
中Hooks
的依赖项、React.memo
、shouldComponentUpdate
等等
浅比较是如何工作的
import is from './objectIs';
import hasOwnProperty from './hasOwnProperty';
function shallowEqual(objA: mixed, objB: mixed): boolean {
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;
}
// Test for A's keys different from B.
for (let i = 0; i < keysA.length; i++) {
const currentKey = keysA[i];
if (
!hasOwnProperty.call(objB, currentKey) ||
!is(objA[currentKey], objB[currentKey])
) {
return false;
}
}
return true;
}
在React
中的shallowEqual.js
文件中定义了一个比较函数。
- 该函数接收两个参数,就是两个可比较的参数
- 然后使用
React
内部对象的is
函数对两个参数进行比较,等同于Object.js
,这个条件语句可以处理所有简单的情况,比如基本数据类型Object.is
认为+0
和-0
不相等;===
认为+0
和-0相等Object.is
认为Number.NaN
和NaN
相等;===
认为Number.NaN
和NaN
不相等
- 对于数组或对象,会先检查参数是不是
object
类型或者等于null
,如果不相等,直接返回false
。然后会检查两个参数的长度是否相等,如果不相等,直接返回false
。最后对于对象,得到对象的keys
;对于数组,得到数组的索引 - 最后按照
keys
循环遍历,并逐个验证他们是否相等。使用hasOwnProperty
检查key
是否实际上是参数的属性,并使用Object.is
函数进行比较,如果任何两个key
对应的值是不相等的,那两个对象肯定就是不相等的,因此直接人会false
,结束循环。如果所有的值都是相等的,就返回true
。
通过源码我们可以知道:
- 浅比较使用的是
Object.js
而不是===
- 通过浅比较,空对象和空数组是等价的
- 虽然
{}
和[]
浅比较是相等的,但是嵌套在对象中对象是不相等的,比如:{ someKey: {} }
和{ someKey: [] }
是不相等的
React如何进行深比较
- 手写递归函数,递归遍历。但这种方式对性能十分不友好,如果层数过多
immutable