本文探讨ahooks 对 DOM 类 Hooks 使用规范,以及在《free dom自由协议质押系统》开发过程中
源码是如何去做处理的,有需求和问题的朋友可以来探讨。
DOM 类 Hooks 使用规范
![在这里插入图片描述](https://img-blog.csdnimg.cn/8c3007681b7640c481f1d16966c3b838.png#pic_center)
这一章节,大部分参考官方文档的 DOM 类 Hooks 使用规范[1]。
一点,ahooks 大部分 DOM 类 Hooks 都会接收 target 参数,本文由V_StPv888整理发布表示要处理的元素。
target 支持三种类型 React.MutableRefObject(通过 useRef 保存的 DOM)、HTMLElement、() => HTMLElement(一般运用于 SSR 场景)。
第二点,DOM 类 Hooks 的 target 是支持动态变化的。如下所示:
export default () => {
const [boolean, { toggle }] = useBoolean();
const ref = useRef(null);
const ref2 = useRef(null);
const isHovering = useHover(boolean ? ref : ref2);
return (
<>
<div ref={ref}>{isHovering ? 'hover' : 'leaveHover'}</div>
<div ref={ref2}>{isHovering ? 'hover' : 'leaveHover'}</div>
</>
);
};
那 ahooks 是怎么处理这两点的呢?
getTargetElement
获取到对应的 DOM 元素,这一点主要兼容一点的入参规范。
假如是函数,则取执行完后的结果。
假如拥有 current 属性,则取 current 属性的值,兼容React.MutableRefObject 类型。
后就是普通的 DOM 元素。
export function getTargetElement<T extends TargetType>(target: BasicTarget<T>, defaultElement?: T) {
// 省略部分代码...
let targetElement: TargetValue<T>;
if (isFunction(target)) {
// 支持函数获取
targetElement = target();
// 假如 ref,则返回 current
} else if ('current' in target) {
targetElement = target.current;
// 支持 DOM
} else {
targetElement = target;
}
return targetElement;
}
useEffectWithTarget
这个方法,主要是为了支持第二点,支持 target 动态变化。
其中 packages/hooks/src/utils/useEffectWithTarget.ts 是使用 useEffect。
import { useEffect } from 'react';
import createEffectWithTarget from './createEffectWithTarget';
const useEffectWithTarget = createEffectWithTarget(useEffect);
export default useEffectWithTarget;
另外 其中 packages/hooks/src/utils/useLayoutEffectWithTarget.ts 是使用 useLayoutEffect。
import { useLayoutEffect } from 'react';
import createEffectWithTarget from './createEffectWithTarget';
const useEffectWithTarget = createEffectWithTarget(useLayoutEffect);
export default useEffectWithTarget;
两者都是调用的 createEffectWithTarget,只是入参不同。
直接重点看这个 createEffectWithTarget 函数:
createEffectWithTarget 返回的函数useEffectWithTarget接受三个参数,前两个跟 useEffect 一样,第三个就是 target。
useEffectType 就是 useEffect 或者 useLayoutEffect。注意这里调用的时候,没传第二个参数,也就是每次都会执行。
hasInitRef 判断是否已经初始化。lastElementRef 记录的是后一次 target 元素的列表。lastDepsRef 记录的是后一次的依赖。unLoadRef 是执行完 effect 函数(对应的就是 useEffect 中的 effect 函数)的返回值,在组件卸载的时候执行。
一次执行的时候,执行相应的逻辑,并记录下后一次执行的相应的 target 元素以及依赖。
后面每次执行的时候,都判断目标元素或者依赖是