第三期: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-useEffect
  • why:如下图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所示
javascript 复制代码
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 排版

相关推荐
小李小李不讲道理7 小时前
「Ant Design 组件库探索」四:Input组件
前端·javascript·react.js
知识分享小能手14 小时前
React学习教程,从入门到精通,React AJAX 语法知识点与案例详解(18)
前端·javascript·vue.js·学习·react.js·ajax·vue3
NeverSettle_19 小时前
React工程实践面试题深度分析2025
javascript·react.js
学前端搞口饭吃20 小时前
react reducx的使用
前端·react.js·前端框架
努力往上爬de蜗牛20 小时前
react3面试题
javascript·react.js·面试
开心不就得了20 小时前
React 进阶
前端·javascript·react.js
谢尔登20 小时前
【React】React 哲学
前端·react.js·前端框架
学前端搞口饭吃1 天前
react context如何使用
前端·javascript·react.js
GDAL1 天前
为什么Cesium不使用vue或者react,而是 保留 Knockout
前端·vue.js·react.js
Dragon Wu1 天前
React state在setInterval里未获取最新值的问题
前端·javascript·react.js·前端框架