前阵子了解到了 ahooks 这个库(好像了解的有点晚🤦♂️),粗略看了看文档,感觉这个东西有点赞啊,尤其是 useVirtualList 更是让我开了眼界,此处应有黑蒜姐的哇~。原来 hook 不止是可以封装逻辑,甚至是 ui 也能一起处理,真的是学到了。
好吧,那就废话少说,开始整活。下面所说的源码为 ahooks v2.10.3 版本
为了和代码原始注释区分,个人理解部分使用 ///
开头,此处和 三斜线指令没有关系,只是为了做区分。
先说结论
个人认为大部分的 hook 都是很实用的,很多都是用来解决实际生产中会遇到的需求。大家先粗略看看都有什么 hook,然后在实际生产过程中有遇到类似的需求可以直接拿来就用。
由于目前项目是 react + antd 技术栈,所以优先推荐的有:useAntdTable 、useMount、useUpdateEffect、useUrlState、useLocalStorageState 和 useSafeState 等。其他的感觉是针对细分场景的,可以不用花过多的时间去了解,遇到了再看就行了。
首先我们来看看 Advanced 部分的 hooks。
Advanced
useCreation
升级版的 useRef,用于创建常量。
import { useRef } from 'react';
export default function useCreation<T>(factory: () => T, deps: any[]) {
const { current } = useRef({
deps, /// 存储上一次的依赖数组
obj: undefined as undefined | T, /// 工厂函数生产的目标值
initialized: false, /// 是否已经初始化
});
if (current.initialized === false || !depsAreSame(current.deps, deps)) {
current.deps = deps;
current.obj = factory();
current.initialized = true;
}
return current.obj as T;
}
/// 通过 === 按顺序对依赖数组逐项对比,并且只会对比第一层,所以如果依赖是个对象或者数组,想要更新必须要改变引用地址
function depsAreSame(oldDeps: any[], deps: any[]): boolean {
if (oldDeps === deps) return true;
for (let i = 0; i < oldDeps.length; i++) {
if (oldDeps[i] !== deps[i]) return false;
}
return true;
}
useCreation 主要是利用了 useRef 的一个重要性质:返回的 ref 对象在组件的整个生命周期内保持不变。这种用法在我一开始看 react 的文档时是没有注意到的,还以为是和以前一样仅仅用作 dom 访问。这里我再详细介绍一下这个性质,因为 ahooks
中大量使用了这个特性,如果没有很好的理解这个原理,阅读起来总会感觉有点不明所以。
useRef
useRef 返回一个可变的 ref 对象,其 .current
属性被初始化为传入的参数(initialValue
)。返回的 ref 对象在组件的整个生命周期内保持不变。而且当 ref 对象内容发生变化时,useRef
并不会通知你。变更 .current
属性不会引发组件重新渲染。
所以说useRef()
比 ref
属性更有用。它可以很方便地保存任何可变值,其类似于在 class 中使用实例字段的方式。
但是如果这个值需要进行懒加载计算,useRef()
就不太适合了,因为useRef
不会 像 useState
那样接受一个特殊的函数重载。这也是为什么会有上面的useCreation
自定义 hook
的原因,useCreation
可以说是如何惰性创建昂贵的对象?的一种抽象实现。
以上内容由于本人水平问题难免有误,欢迎大家进行讨论反馈。
第一次在掘金发文章,也不熟悉情况,欢迎大家多多点赞评论转发!