【源码阅读_hook】如何封装一个useFetch?(axios版)

之前写过一篇文章,介绍vueuse库里面的useFetch的用法。 # 【源码阅读】比官网更全的useFetch使用方式(超详细)

当时是因为想试一下useFetch到底好不好用,然后去翻了官网发现有很多用法文档并没有写,所以干脆看源总结了一下useFetch用法。

当时这事就暂时告一段落了。

直到最近有个小项目,想自己封装一个基于axios的hook,于是再去看源码,发现了很多很有意思的细节。

这篇文章跟大家分享一下。

至于为什么不直接用useFetch?

一来是,我一直用axios,比较习惯axiso的用法,useFetch每次传参我都有点犹豫,不太习惯。

二来是公司项目接口没有那么规范,用axios更方便一点。(比如delete请求,经常是params参数也有,body参数也有)

三来是,axios上传文件啥的做进度条比较方便。

anywhy, 就是有这么个需求。


一开始封装的挺顺利的,结构参考useFetch源码。

1.接口请求取消

axios是有自己的取消用法的,可以通过axios.CancelToken来实现。

ini 复制代码
const source = axios.CancelToken.source();
axios({
    cancelToken: source.token
})
source.cancel('');

在hook里面,只要url没有变,则为同一个请求。比如一模一样的接口,我同时请求2次。

那么,第一次的请求就应该取消(如果请求未结束的话),只执行第二次接口请求。

参考一下源码的实现。(只要上一次请求isFetching未结束,则执行取消,并设置新的signal。)

逻辑很简单吧,但是用axios.CancelToken来实现,会出现两次均取消,或者两次均发送的问题。(也就是重新设置source并未生效)

找了一圈,也没有好的解决方案(有大神如果知道,可以留言指导一下),最后还是跟源码一样,采用AbortController的方式。

2.hook返回promise

一个基础的hook使用方式,如下(自己封装的版本)

php 复制代码
const { execute, loading, data, error } = useRequest(
  Auth_API,
  {
    method: "post",
  },
  {
    immediate: false,
    beforeRequest: async (ctx) =>
      (ctx.options.params = {
        channel: channel.value,
        code: code.value,
      }),
  },
);

useRequest的返回结果是一个对象,包含各个状态值。

但是既然是异步的api请求,就会有要求同步执行的需求。(比如先后执行的两个接口,等待接口返回数据做二次处理等)

那么如何,既返回对象,又是promise呢?

答案就是给对象加一个then方法,比如如下demo。

javascript 复制代码
function myFunction() {
  const myObject = {
    then: function(onFulfill, onReject) {
      // 在这里可以进行异步操作
      setTimeout(function() {
        onFulfill('Hello, World!');
      }, 1000);
    }
  };
  
  return myObject;
}

async function example() {
  try {
    const result = await myFunction();
    console.log(result); // 将在 Promise 解析后输出 'Hello, World!'
  } catch (error) {
    console.error(error);
  }
}

example();

所以当需要同步执行的时候,只要在then里面把状态值再返回即可。

3.如何判断接口已经执行完毕?

then方法已经有了,那么如何判断接口已经执行完毕了呢?

方法很简单,大家肯定也都知道。

设置一个变量就好了嘛,请求前设置false,请求完毕设置为true。(也就是isFinished变量)

那么这种方式行不行呢?

scss 复制代码
if(isFinished.value) {
  onFulfilled({})
}

肯定不行,对吧。

哪怕isFinished值改变了,也不会触发onFulfilled。

那怎么办呢?

看看源码是怎么实现的。

scss 复制代码
  return {
    ...shell,
    then(onFulfilled, onRejected) {
      return waitUntilFinished()
        .then(onFulfilled, onRejected)
    },
  }
  
    function waitUntilFinished() {
    return new Promise<UseFetchReturn<T>>((resolve, reject) => {
      until(isFinished).toBe(true)
        .then(() => resolve(shell))
        .catch(error => reject(error))
    })
  }

关键就在这个until上了。

其实核心就是这个watcher对吧。

通过watch这个api来触发。

因为是自己使用,功能也不用那么强大,我封装一个简易版不就了嘛。(用完记得销毁)

javascript 复制代码
function until() {
    let stop: Function | null = null;
    return new Promise((resolve) => {
      stop = watch([isFinished], ([v1]) => {
        if (v1 === true) {
          stop?.();
          resolve(v1);
        }
      });
    });
  }

  function waitUntilFinished() {
    return new Promise<UseRequestReturn<T>>((resolve, reject) => {
      until()
        .then(() => resolve(shell))
        .catch((error) => reject(error));
    });
  }

总结一下

hook虽然不复杂,但是真到自己封装的时候,好多细节还是会有遗漏。

还有一些代码看懂了,但是不知道为啥要加的一些功能,自己封装一下感受又深了几分。

源码比较多,感兴趣的可以点击参考地址

如果需要运行查看,需要安装脚手架,执行init命令,选择vue模板即可。(因为项目是模板代码,使用了ejs)

css 复制代码
npm i -g @bubu-cli/cli

b init

先到这吧。

后续如果有新的感悟,或者对架构有新的思考再分享。

如果这篇文章对你有所收获,欢迎点赞评论。

相关推荐
并不会42 分钟前
常见 CSS 选择器用法
前端·css·学习·html·前端开发·css选择器
衣乌安、1 小时前
【CSS】居中样式
前端·css·css3
兔老大的胡萝卜1 小时前
ppk谈JavaScript,悟透JavaScript,精通CSS高级Web,JavaScript DOM编程艺术,高性能JavaScript pdf
前端·javascript
低代码布道师1 小时前
CSS的三个重点
前端·css
耶啵奶膘2 小时前
uniapp-是否删除
linux·前端·uni-app
王哈哈^_^4 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie4 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic5 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿5 小时前
webWorker基本用法
前端·javascript·vue.js
cy玩具6 小时前
点击评论详情,跳到评论页面,携带对象参数写法:
前端