当前位置:网站首页>Record the first PR to an open source project
Record the first PR to an open source project
2022-08-01 21:03:00 【GopalFeng】
本文是深入浅出 ahooks 源码系列文章的第八篇,这个系列的目标主要有以下几点:
- 加深对 React hooks 的理解.
- 学习如何抽象自定义 hooks.构建属于自己的 React hooks 工具库.
- 培养阅读学习源码的习惯,工具库是一个对源码阅读不错的选择.
注:本系列对 ahooks 的源码解析是基于 v3.3.13
.自己 folk 了一份源码,主要是对源码做了一些解读,可见 详情[1].
本篇文章算是该系列的一个彩蛋篇,记录一下第一次给开源项目提 PR 的过程(之前好像也有过,不过那个非常小的一个改动),希望能够帮助更多的人参与到开源项目中来.
起因
在写了几篇关于 ahooks 的文章之后,收到了官方同学的私信.
这让我受宠若惊的同时也有点小兴奋和惶恐.
兴奋是,之前感觉参与开源是一件遥不可及的事情,现在似乎我也能够去做了.当然也有私心,假如我的简历上有给开源项目做贡献的经历,那岂不是一个不错的加分项?
惶恐的是,我之前没有参与过开源项目,担心自己不能做好这件事.
根据大佬的建议,我决定先从一些 issue 入手,也就是帮忙解决一下 issue.
明确问题OR需求
于是我抱着试试看的态度,看了一下官方的 issue,看到这么一条.issue 详情[2].
刚好我之前对 useRequest 源码做过一些分析——如何使用插件化机制优雅的封装你的请求[3].于是我决定 fix 一下这个 issue.
这个 issue 的需求很简单,就是希望轮询失败后,能够支持最大的轮询次数,假如失败的次数大于这个值,则停止轮询.
编码前准备
首先,从 ahooks 官方 GitHub 中 folk 一份.这个操作我之前已经做了.
第二步,基于 master 切换一个功能分支.如下:
git checkout -b fix/pollingSupportRetryCount
最后就是环境的一些初始化操作,不同的仓库不同,ahooks 如下:
yarn run init
yarn start
功能实现
我们先来看下现在 useRequest 的轮询的实现,其原理主要是在一个请求结束的时候(不管成功与失败),通过 setTimeout 进行重新请求,达到轮询的效果.
onFinally: () => {
// 省略部分代码...
// 通过 setTimeout 进行轮询
timerRef.current = setTimeout(() => {
fetchInstance.refresh();
}, pollingInterval);
},
我的想法是,定义一个 options 参数,pollingErrorRetryCount
,默认为 -1,代表没有限制.
另外定义一个变量,记录当前重试的次数:
const countRef = useRef<number>(0);
当开发者设置了 pollingErrorRetryCount,并且重试的数量大于该值,我们就直接返回,不执行轮询的逻辑.
当成功或者失败的时候,更新当前重试的次数:
onError: () => {
countRef.current += 1;
},
onSuccess: () => {
countRef.current = 0;
},
然后在请求结束的时候,判断重试的次数有没有达到了开发设置的次数,假如没有则执行重试操作.有则重置重试的次数,停止轮询.
onFinally: () => {
if (
pollingErrorRetryCount === -1 ||
// When an error occurs, the request is not repeated after pollingErrorRetryCount retries
(pollingErrorRetryCount !== -1 && countRef.current <= pollingErrorRetryCount)
) {
// 忽略部分代码
timerRef.current = setTimeout(() => {
fetchInstance.refresh();
}, pollingInterval);
} else {
countRef.current = 0;
}
},
测试用例
上述整体的改造并不困难,但是我在写测试用例的时候,就开始踩坑了,因为我很少书写前端的测试用例,还是针对于 hooks 的测试用例.这里是我耗时最多的地方.
最终用例如下:
// 省略部分代码...
// if request error and set pollingErrorRetryCount
// and the number of consecutive failures exceeds pollingErrorRetryCount, polling stops
let hook2;
let errorCallback;
act(() => {
errorCallback = jest.fn();
hook2 = setUp(() => request(0), {
pollingErrorRetryCount: 3,
pollingInterval: 100,
pollingWhenHidden: true,
onError: errorCallback,
});
});
expect(hook2.result.current.loading).toEqual(true);
expect(errorCallback).toHaveBeenCalledTimes(0);
act(() => {
jest.runAllTimers();
});
await hook2.waitForNextUpdate();
expect(hook2.result.current.loading).toEqual(false);
expect(errorCallback).toHaveBeenCalledTimes(1);
act(() => {
jest.runAllTimers();
});
await hook2.waitForNextUpdate();
expect(errorCallback).toHaveBeenCalledTimes(2);
act(() => {
jest.runAllTimers();
});
await hook2.waitForNextUpdate();
expect(errorCallback).toHaveBeenCalledTimes(3);
act(() => {
jest.runAllTimers();
});
await hook2.waitForNextUpdate();
expect(errorCallback).toHaveBeenCalledTimes(4);
act(() => {
jest.runAllTimers();
});
expect(errorCallback).toHaveBeenCalledTimes(4);
act(() => {
hook2.result.current.run();
});
act(() => {
jest.runAllTimers();
});
await hook2.waitForNextUpdate();
expect(errorCallback).toHaveBeenCalledTimes(5);
hook2.unmount();
// 省略部分代码...
大致解释下该测试用例的逻辑,我设置了重试三次,错误之后,运行了三次,errorCallback
就会被调用了 4 次(包括错误那次).在第五次执行的时候,就不会执行 errorCallback
,也就还是 4 次.然后我们手动 run 一次请求,期待 errorCallback
应该执行 5 次.
这里踩了一个坑,就是第五次请求的时候,我之前是会写一个等待定时器执行的操作,但实际上这里它是不会执行定时器的,导致一直报错,在这里折腾了很久.后来删除了下面的代码才执行成功.
act(() => {
jest.runAllTimers();
});
- await hook2.waitForNextUpdate();
expect(errorCallback).toHaveBeenCalledTimes(4);
文档以及 Demo 补充
毕竟加了一个新的 API 参数,需要在文档中注明,而且中英文文档都需要补充,还加上了一个 Demo 示例.
提 PR
上述都完成之后,就可以提交你的代码了,提交完,去到在你 folk 过来的项目中,可以看到这个.
我们需要点击图中框起来的「Compare & pull request 」,之后就会出现如下图
图来自网络,演示用
默认会帮我们选好分支的,我们只需要完善其中的信息,还有我们之前提交的 message 也可以修改.最好可以用英文来解释,本次提交的内容.
最后点击提交之后就好了.
还有一个提 PR 的入口,如下所示:
最后等待官方 CR 就可以了(上面的实现其实部分是 CR 后改的).目前该 PR 已经被合入到 master.
总结思考
给开源项目提 PR 操作过程不是一件很复杂的事情,重点在于需求的修改.往往需要考虑到多种边界场景,这个时候,我们就需要前端的单元测试来帮助我们覆盖全面的场景.
另外,对于一些还没有参与开源项目经验的同学来讲,我觉得类似 ahooks 这种工具库是一个不错的选择:
- 它的模块划分更加清晰,你改了一个模块的功能,影响面可以更好的预估.对新人比较友好.
- 逻辑相对简单,其实你会发现很多代码说不定在你们的业务项目中的 utils/hooks 文件夹中就有.
- 社区比较活跃,维护者能够较快的响应.
希望对大家有所帮助.
系列文章:
- 大家都能看得懂的源码(一)ahooks 整体架构篇[4]
- 如何使用插件化机制优雅的封装你的请求hook [5]
- ahooks 是怎么解决 React 的闭包问题的?[6]
- ahooks 是怎么解决用户多次提交问题?[7]
- ahooks 中那些控制“时机”的hook都是怎么实现的?[8]
- 如何让 useEffect 支持 async...await?[9]
- 如何让定时器在页面最小化的时候不执行?[10]
参考资料
[1]详情: https://github.com/GpingFeng/hooks
[2]issue 详情: https://github.com/alibaba/hooks/issues/1645
[3]如何使用插件化机制优雅的封装你的请求: https://juejin.cn/post/7105733829972721677
[4]大家都能看得懂的源码(一)ahooks 整体架构篇: https://juejin.cn/post/7105396478268407815
[5]如何使用插件化机制优雅的封装你的请求hook : https://juejin.cn/post/7105733829972721677
[6]ahooks 是怎么解决 React 的闭包问题的?: https://juejin.cn/post/7106061970184339464
[7]ahooks 是怎么解决用户多次提交问题?: https://juejin.cn/post/7106461530232717326
[8]ahooks 中那些控制“时机”的hook都是怎么实现的?: https://juejin.cn/post/7107189225509879838
[9]如何让 useEffect 支持 async...await?: https://juejin.cn/post/7108675095958126629
[10]如何让定时器在页面最小化的时候不执行?: https://juejin.cn/post/7109399243202232357
边栏推荐
- JSD-2204-Knife4j框架-处理响应结果-Day07
- Godaddy domain name resolution is slow and how to use DNSPod resolution to solve it
- Internet使用的网络协议是什么
- 扣减库存方案
- MySQL 中出现的字符编码错误 Incorrect string value: ‘\x\x\x\x‘ for column ‘x‘
- 【Kaggle】Classify Leaves
- LinkedList源码分享
- What is the difference between a utility model patent and an invention patent?Understand in seconds!
- AQS原理和介绍
- 有点奇怪!访问目的网址,主机能容器却不行
猜你喜欢
面试突击70:什么是粘包和半包?怎么解决?
Internet使用的网络协议是什么
What is the difference between a utility model patent and an invention patent?Understand in seconds!
数据库内核面试中我不会的问题(1)
MySQL 中出现的字符编码错误 Incorrect string value: ‘\x\x\x\x‘ for column ‘x‘
【Kaggle】Classify Leaves
Pytorch框架学习记录8——最大池化的使用
4.1 配置Mysql与注册登录模块
Interview Blitz 70: What are sticky packs and half packs?How to deal with it?
技能大赛训练:A部分加固题目
随机推荐
Pytorch框架学校记录11——搭建小实战完整细节
Buttons with good user experience should not have hover state on mobile phones
字符串
4.1 配置Mysql与注册登录模块
C陷阱与缺陷 第7章 可移植性缺陷 7.8 随机数的大小
列表页常见的 hook 封装
win10版本1803无法升级1903系统如何解决
pytest:开始使用
vant实现Select效果--单选和多选
Godaddy域名解析速度慢问题以及如何使用DNSPod解析解决
封装一个管理 url 状态的 hook
分类接口,淘宝分类详情 API
【Kaggle】House Prices
excel高级绘图技巧100讲(二十二)-如何对不规则数据进行分列
Protocol Buffer usage
线上问题排查常用命令,总结太全了,建议收藏!!
写给刚进互联网圈子的人,不管你是开发,测试,产品,运维都适用
tiup mirror merge
附录A printf、varargs与stdarg A.2 使用varargs.h来实现可变参数列表
有点奇怪!访问目的网址,主机能容器却不行