首页 > 其他分享 >记录第一次给开源项目提 PR

记录第一次给开源项目提 PR

时间:2022-08-18 21:12:49浏览次数:69  
标签:PR 记录 hook2 current 开源 expect act errorCallback

本文是深入浅出 ahooks 源码系列文章的第八篇,该系列已整理成文档-地址。觉得还不错,给个 star 支持一下哈,Thanks。

本篇文章算是该系列的一个彩蛋篇,记录一下第一次给开源项目提 PR 的过程(之前好像也有过,不过那个非常小的一个改动),希望能够帮助更多的人参与到开源项目中来。

起因

在写了几篇关于 ahooks 的文章之后,收到了官方同学的私信。

这让我受宠若惊的同时也有点小兴奋和惶恐。

兴奋是,之前感觉参与开源是一件遥不可及的事情,现在似乎我也能够去做了。当然也有私心,假如我的简历上有给开源项目做贡献的经历,那岂不是一个不错的加分项?

惶恐的是,我之前没有参与过开源项目,担心自己不能做好这件事。

根据大佬的建议,我决定先从一些 issue 入手,也就是帮忙解决一下 issue。

明确问题OR需求

于是我抱着试试看的态度,看了一下官方的 issue,看到这么一条。issue 详情

刚好我之前对 useRequest 源码做过一些分析——如何使用插件化机制优雅的封装你的请求。于是我决定 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,
    one rror: 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 文件夹中就有。
  • 社区比较活跃,维护者能够较快的响应。

希望对大家有所帮助。

标签:PR,记录,hook2,current,开源,expect,act,errorCallback
From: https://www.cnblogs.com/gopal/p/16600120.html

相关文章

  • prometheus钉钉告警
    钉钉添加机器人将webhook复制到脚本中点一下加签复制保存下后面有用配置告警脚本[root@harborapps]#catdingding-keywords.sh#!/bin/bashsource/etc/prof......
  • 【DP 记录】AcWing 734. 能量石
    传送门给你几个物品,每种选一次,求最大价值,首先想到01背包,但是我们遇到了一个问题:普通的01背包在选择物品时是不讲求顺序的,但在这道题中,物品的选择是有顺序的(即对最优......
  • 闭包和promise
    闭包概述:闭包是一种书写代码一种结构,这种结构拥有的特性就是内部的空间在使用中不会被回收。(内部的变量以及对应的参数不会被gc回收)函数的预编译过程开辟函数的内存空......
  • Function eregi() is deprecated (解决方法)
    在php升级到php5.3之后后,在使用的过程经常发现有的程序会出现Functioneregi()isdeprecated的报错信息。是什么原因呢?这是因为php5.3中不再支持eregi()函数,而使用preg_m......
  • MyBatis核心配置文件详解、添加properties文件
    1.mybatis-config.xml文件详解<environmentsdefault="development">environments:配置连接数据库的环境属性:default:设置默认使用环境的id。可以有多个环境,像开......
  • C++primer练习15.1-14
    练习15.1什么是虚成员?::需要派生类自己定义的成员练习15.2protected访问说明符与private有何区别?::protected允许派生类访问,private一律不允许访问练习15.3定义你自己的......
  • Spring和SpringMVC的常用注解
    Spring和SpringMVC的常用注解1.Spring相关注解 1.1声明bean的注解@Component通用注解,用于声明bean。可以配置任意组件。@Repository派生注解,与@Component等效,Dao......
  • Java开发学习(二十六)----SpringMVC返回响应结果
    SpringMVC接收到请求和数据后,进行了一些处理,当然这个处理可以是转发给Service,Service层再调用Dao层完成的,不管怎样,处理完以后,都需要将结果告知给用户。比如:根据用户ID查......
  • springboot实现多级嵌套并返回json格式的数据处理
    菜单功能列表嵌套菜单解决方案本文目录       菜单功能列表嵌套菜单解决方案           1、通过mapper定义sql的自循环,在查询时就完成菜单的嵌套  ......
  • protobuf3 标量数据类型
    标量数据类型消息标量字段可以是以下类型之一——下表列出了可以用在.proto文件中使用的类型,以及在生成代码中的相关类型:.protoTypeNotesC++TypeJavaTypePython......