第三期:ahooks全讲解-Part1
hello,我是海海
从这一期我们将开启一个新的旅程——
ahooks
。阅读时间10分钟。由于
ahooks
内容比较多,我将拆分成几个章节,本期我们先从整体的角度认识ahooks
,并讲解比较简单的“开发”hooks和“生命周期”hooks。不同于其他介绍
ahooks
的文章,本系列会对每一个hook从what
(是什么)、how
(怎么用)、why
(实现原理)、when
(啥时候用)做全方面的讲解。欢迎转载,请注明原文和作者
有任何不对的地方,欢迎底部发消息给我。
本期大纲:
-
ahooks
:react hooks的扩展 -
别急,让我们整体认识
ahooks
-
从dev-hooks开始
useTrackedEffect
(GPS定位装置)useWhyDidYouUpdate
(我徒弟呢?我不到啊!)
-
别忘了,还有lifecycle-hooks
useMount
(挂载之后)useUnmount
(卸载之前)useUnmountedRef
(查询是否卸载)
有点懵圈,让我们开始吧!
ahooks:hooks的扩展
2018年,React
v16.8版本发布,hooks
作为引入的一个新特性,允许开发者在不使用class
的情况下使用state
和其他React
特性。这些hooks
似乎足够我们使用,就像乐高的积木,这些都是最基础的功能。等到了复杂的业务场景,我们就需要组合、复用这些hooks
。
2019年8月,阿里发布了ahooks
库v0.1.0。当时只有包含useAPI(现在是useRequest)等5个hooks。
2019年9月,在仅过了一个月之后,v1版本正式发布。hooks数量增加到了8个。
2020年6月,v2版本发布,hooks
数量快速增长,到达了31个。其中一个重大的修改,是使用userRequest替换了6个hooks。
2021年12月,v3版本发布。
2022年3月,React
v18版本发布。至此,React hooks
已有长足的发展。我们在前几期的文章中粗略的描述了这些hooks的功能。
截止到2023年7月,ahooks已经包括了以下不同类别的76个hooks:
- 强大的
useRequest
DOM
(DOM操作)Scene
(业务)State
(状态)Effect
(副作用)Dev
(开发模式)Advanced
(高级)LifeCycle
(组件生命周期)
从dev-hooks开始
Dev 类别下只有2个hooks,比较简单。我们从这里开始我们的旅程。
【v2.9.0添加】
useTrackedEffect
(GPS定位装置)
what
:当useEffect变化时,追踪是哪个依赖触发的how
:用法与useeffect相同,回调函数添加触发依赖的参数when
:debug-useEffectwhy
:如下图1-1和图1-2所示
图1-1:useTrackedEffect关键代码
图2-2:useTrackedEffect核心原理
useTrackedEffect
关键代码如图1-1所示,这里忽略了typescript类型和diffTwoDeps算法函数。
算法流程和原理可以参考图1-2。
通过map方法遍历和Object.is方法比较新旧的依赖项,输出对应的产生改变的依赖的索引下标。
这里有必要对Object.is进行下讲解,都说Object.is是浅比较的意思,那么什么是浅比较?
浅比较关注比较对象的引用是否相同,深比较关注的是值是否相同。所以,对这个useTrackedEffect
来说,只要依赖的引用不变,就不会触发回调函数,这一点和useEffect
相同。
看到这里的时候,我产生了我上我也行的幻觉!
【v2.2.0添加】
useWhyDidYouUpdate
(我徒弟呢?我不到啊!)
what
:追踪哪一个状态、属性触发组件rerender(重渲染)how
:自定义字符串表示debug的组件名字;一个需要追踪的属性或者状态对象;when
:debug组件渲染why
:如下图1-3和图1-4所示
图1-3:useWhyDidYouUpdate关键代码
图1-4:useWhyDidYouUpdate基本原理
这个hooks设计的绝妙之处就在于利用了useEffect
在没有依赖数组时会每次执行!
同时在这里,我们又看到了useRef
用来存储上一次的值。
我徒弟呢?
当你的组件找不到"徒弟"时,可以试试
useWhyDidYouUpdate
。
别忘了,还有lifecycle-hooks
虽然我们有了hooks可以免于编写类组件的痛苦,但是有时候我们又想利用类组件的生命周期做些事情。
我们可以利用下面的生命周期hooks。
【v1.8.0添加】
useMount
(挂载之后)
-
what:和
componentDidMount`用法相同 -
how
:无参回调函数 -
when
:- 添加事件监听、订阅事件
- 添加定时器
- 发送请求,初始化组件数据
- 获取元素的尺寸和位置
-
why
:如下图1-5和图1-6所示
图1-5:useMount关键代码
图1-6:useMount基本实现
可以看到useMount只是对useEffect做了一层包装。
此外,useMount还对参数做了typeof判断是否为函数,但是我感觉是多余的,为什么不直接用useEffect去处理!知道的同学可以在评论区留言给我。
【v1.7.0添加】
useUnmount(卸载之前)
-
what:和
componentWillUnMount
用法相同 -
how:无参回调函数
-
when:
- 移除事件监听、取消订阅事件
- 清除定时器
- 中断/取消异步操作
-
why:如下图1-7和图1-8所示
图1-7:useUnmount关键代码
图1-8:useUnmount核心逻辑
这个hook的原理也很简单,和useMount异曲同工,都是利用了useEffect的特性,只不过这里使用了useEffect的回调函数返回值。
到这里,我们其实明白了,lifecycle这一部分的本质是对useEffect做了拆解,说明充分了解useEffect的原理和使用对我们了解ahooks是有帮助的。
【v2.10.8添加】
useUnmountedRef(查询某组件是否卸载了)
- what:查询组件的状态(卸载/没卸载)
- how:在要查询的组件中使用该hook,通过获取xx.current(xx是hook的返回值)的布尔值,得到组件是否被卸载。具体使用见下方代码。
- when:异步函数在获取到结果后,可能需要判断组件是否被卸载(我很少碰到这种情况,又碰到的同学可以在评论区留言)
- why:如下图1-9和图1-10所示
const MyComponent = () => {
const unmountedRef = useUnmountedRef();
useEffect(() => {
setTimeout(() => {
// 如果组件已经被卸载,则此部分代码无法访问被卸载的组件。
// 但是可以通过useUnmountedRef返回的闭包,获取到组件的信息
// hook本质:一个闭包
if (!unmountedRef.current) {
message.info('component is alive');
}
}, 3000);
}, []);
return <p>Hello World!</p>;
};
图1-9:useUnmountedRef关键代码
图1-10:useUnmountedRef算法核心
可以看到,这个实现的原理其实非常简单。无非是在组件中利用了useEffect返回值和useRef引用不变的特性。但是加在一起就变成了有用的东西。
好了,今天的旅程到这里就结束了,谢谢你的陪伴!
感谢你的耐心阅读,如果觉得好的话,可以给我点个赞吗
创作不易,感谢你的支持!
本文使用 markdown.com.cn 排版
转载自:https://juejin.cn/post/7261521980019572792