当依赖是基本数据类型的时候,因为是值比对,所以直接写就好了。但是如果依赖数据是对象或者数组。此时 useEffect 检测的是内存地址是否不同。而实际业务中,基本上也只要比对对象和数组中的值是否相同。正确的写法能减少组件刷新次数,从而优化性能
方法1、
使用 ahooks 中的 useDeepCompareEffect 进行处理
源码解析
- 思路:虽然调用 useEffect 的时候传递的依赖是数组或者对象,但是我们可以将其改造成基础数据类型
- 创建2个 ref 对象,一个用来记录上一次的依赖参数,另外一个 signalRef 设置成基础数据类型,用来触发 useEffect。使用 lodash 中的 isEqual 来检测2次依赖是否完全相同,不同的时候就将 signalRef 中的数字加1触发 useEffect 更新
- 简化后的代码如下
import { useRef } from 'react';
import isEqual from 'lodash/isEqual';
const depsEqual = (aDeps, bDeps) => {
return isEqual(aDeps, bDeps);
};
export const createDeepCompareEffect = (hook) => (effect, deps) => {
const ref = useRef();
const signalRef = useRef(0);
if (deps === undefined || !depsEqual(deps, ref.current)) {
ref.current = deps;
signalRef.current += 1;
}
hook(effect, [signalRef.current]);
};
方法2、
使用 react-use 中的 useDeepCompareEffect 进行处理
源码解析
- 创建一个 ref 来记录上一次的依赖参数,ref 初始值为 undefined
- 使用
fast-deep-equal/react将这次的依赖和之前的做深度比对,如果不一致则修改 ref 的值,从而触发 useEffect 的更新
扩展知识点:fast-deep-equal 的使用
npm install fast-deep-equal
var equal = require('fast-deep-equal');
console.log(equal({foo: 'bar'}, {foo: 'bar'})); // true
//支持es6 map set 类型化素组
var equal = require('fast-deep-equal/es6');
console.log(equal(Int16Array([1, 2]), Int16Array([1, 2]))); // true
//搭配react使用
var equal = require('fast-deep-equal/react');
var equal = require('fast-deep-equal/es6/react');