都在说Hooks,快封装一个属于自己的useRequest的吧~

简介: 现在Vue3已经全面拥抱Hooks,如果还不了解或者是什么,赶紧去学学吧,关于Hooks春哥有一篇文章写的很不错:浅谈:为啥vue和react都选择了Hooks🏂?这篇文章已经讲解的非常好了;
Hi~,我是 一碗周,一个在舒适区垂死挣扎的前端,如果写的文章有幸可以得到你的青睐,万分有幸~

🍇 写在前面

现在Vue3已经全面拥抱Hooks,如果还不了解或者是什么,赶紧去学学吧,关于Hooks春哥有一篇文章写的很不错:浅谈:为啥vue和react都选择了Hooks🏂?这篇文章已经讲解的非常好了;

Vue3也有一个比较不错的Hooks的库,也就是VueUse,这个里面有非常多的Hooks,文档的例子也非常的友好,非常建议学习一下。

前一段时间写了一篇封装axios的文章,这篇文章可以说是上篇文章的一个续集,基于封装的axios上在进行一次封装,方便请求。

封装的useRequest已经实现的功能如下:

  • 防抖和节流
  • 轮询
  • 自动请求和手动请求
这篇文章的源代码全部可以再 Github上找到。

🍈 为什么要封装

在实际的开发中,很多请求都需要做一些重复的事情,比如loading、防抖、接口请求结束的提示等等,这些操作基本都是重复的,配合Hooks将这些操作进行封装大大减少了重复代码。

还有就是如果团队使用同一的方式进行请求,如果后期需要对接口请求做一些统一的处理也会更加方便。

🍉 需要的参数

既然要封装,首先需要我们将参数确认一下:

  • 第一个参数是一个异步请求的函数,这里使用之前封装的\`request,你也可以根据自己的需求修改为url或者两者都可以;
  • 第二个参数是请求的参数;
  • 第三个参数就是关于useRequest的一些配置信息了,主要包含以下几项:

    属性 类型 描述 默认值
    debounce boolean 是否开启防抖 false
    debounceInterval number 防抖的时间,单位毫秒 1000
    throttle boolean 是否开启节流 false
    throttleInterval number 节流的时间,单位毫秒 1000
    polling boolean 是否开启轮询 false
    pollingInterval number 轮询的时间,单位毫秒 5000
    autoRun boolean 是否自动调用 true
    onFinish (data: T) => void 接口执行完毕调用的函数 undefined

现在我们将基本的参数定义好了,开始进行封装。

🍊 类型定义

由于我们使用TS进行封装,避免不了要定义一些类型,首先我们定义第三个参数的类型以及useRequest的返回值类型:

import type { Ref } from 'vue'
export interface IUseRequestOption<T = any> {
  // 是否开启防抖 时长
  debounce?: boolean
  debounceInterval?: number
  // 是否开启节流 时长
  throttle?: boolean
  throttleInterval?: number
  // 是否轮询
  polling?: boolean
  pollingInterval?: number
  // 是否自动调用
  autoRun?: boolean
  // 调用完毕可执行的函数
  onFinish?: (data: T) => void
}
export interface IUseRequestRequest<D, T> {
  loading: Ref<boolean>
  data: Ref<T | undefined>
  run: (...args: any[]) => Promise<void> // 手动请求方法
  runParams: (params: D) => Promise<void> // 带参数的请求方法
}

然后我们定义useRequest的基本类型,示例代码如下:

import type { IUseRequestOption, IUseRequestRequest } from './../type'
// 引入返回值类型
import type { YWZResponse } from '/@/service/index'
const useRequest = < // 泛型
  ParamType = any, // 参数的类型
  PromiseRequestType = any, //  返回的data的类型
  DataType = YWZResponse<PromiseRequestType>, // 返回的data的类型的外层
>(
  PromiseRequest: (p: ParamType) => Promise<DataType>, // 异步请求函数
  params: ParamType, // 参数
  opt?: IUseRequestOption<DataType>, // 配置项
): IUseRequestRequest<ParamType, DataType> => {}

export default useRequest

现在我们就可以开始进行编写主要代码了

🍋 开始封装

🍌 处理默认参数

默认参数我们通过Object.assign()方法实现,我们只需要定义一个默认的对象然后进行覆盖即可,示例代码如下:

const defaultOption: IUseRequestOption = {
  // 是否开启防抖 时长
  debounce: false,
  debounceInterval: 1000,
  // 是否开启节流 时长
  throttle: false,
  throttleInterval: 1000,
  // 是否轮询
  polling: false,
  pollingInterval: 5000,
  // 是否自动调用
  autoRun: true,
  // 调用完毕可执行的函数
  onFinish: undefined,
}
const useRequest = <
  ParamType = any,
  PromiseRequestType = any,
  DataType = YWZResponse<PromiseRequestType>,
>(
  PromiseRequest: (p: ParamType) => Promise<DataType>,
  params: ParamType,
  opt?: IUseRequestOption<DataType>,
): IUseRequestRequest<ParamType, DataType> => {
  type Params = ParamType
  // 合并配置项
  const option = Object.assign({}, defaultOption, opt)
  const loading = ref(false)
  const data = ref<DataType>()
  return {
    run: undefined,
    loading,
    data,
    runParams: undefined,
  }
}

🥭 调用和轮询

现在我们封装一下手动调用、自动调用和轮询的功能,这一部分比较简单,先说一下思路吧:

  1. loading设置为true
  2. 调用请求方法,并参数参数;
  3. loading设置为false并调用onFinish
  4. 如果是轮询则在几秒后递归调用。

实现代码如下:

// 调用方法
const run = async (): Promise<void> => {
  loading.value = true
  // 调用请求方法
  data.value = await PromiseRequest(params)

  loading.value = false
  option.onFinish && option.onFinish(data.value)
}
const runParams = async (_params: ParamType): Promise<void> => {
  loading.value = true
  // 调用请求方法
  data.value = await PromiseRequest(_params)

  loading.value = false
  option.onFinish && option.onFinish(data.value)
}
// 轮询
const polling = async () => {
  loading.value = true
  data.value = await PromiseRequest(params)
  loading.value = false
  option.onFinish && option.onFinish(data.value)
  delay(polling, option.pollingInterval as number)
}
// 自动调用
option.autoRun && run()
// 是否轮询
option.polling && polling()

delay方法是lodash中的一个方法,除此之外,下面用到的防抖和节流也是lodash中的方法。

🍎 防抖和节流

防抖和节流我们可以通过计算属性来返回经过防抖或者节流处理过的方法,实现也比较简单,代码如下:

// 计算最终使用的函数
const runComputed = computed(() => {
  // 判断是否开启防抖
  if (option.debounce)
    return {
      run: debounce(run, option.throttleInterval) as () => Promise<void>,
      runParams: debounce(runParams, option.throttleInterval) as (
        p: Params,
      ) => Promise<void>,
    }
  // 判断是否开启节流
  if (option.throttle)
    return {
      run: throttle(run, option.throttleInterval) as () => Promise<void>,
      runParams: throttle(runParams, option.throttleInterval) as (
        p: Params,
      ) => Promise<void>,
    }
  return { run, runParams }
})

最后,我们只要将将处理后的函数进行return即可,示例代码如下:

return {
  run: runComputed.value.run,
  loading,
  data,
  runParams: runComputed.value.runParams,
}

完整代码可以去Github上进行查看。

🍑 测试

现在我们可以对封装的这个Hooks进行测试,测试代码如下:

image_n9AT_-3AWh.png

这个测试代码在Github,你可以换一个API自己试试,看看效果是否跟想象的一样。

关于参数我这里说一下,如果使用方法,想要修改参数后手动调用 API创建的,不然每次调用都会使用默认的参数进行请求。

🍓 写在最后

本篇文章到这为止就结束了,如果你感觉这篇文章对你有用,可以点赞收藏支持一下(点赞的都脱单、暴富);上面的代码全部都在Github中,可以点个star避免迷路。

  • 如果文中有错误欢迎指正\~
  • 如果你有建议欢迎提出\~

最后说一下这个代码还有一个优化的点,就是当参数发生变化后,重新发送请求,实现也比较简单,就是监听params的变化,重新发送请求即可。

目录
相关文章
|
Web App开发 编解码 JavaScript
VUE播放RTSP方案,支持H.265!
VUE播放RTSP方案,支持H.265!如果你问一个前端技术人员,近几年最火的前端框架技术是什么,肯定会有人说VUE,确实VUE凭借其简单特性赢得了大家的喜爱,而近期公司有个项目,需要在VUE框架网页上播放RTSP实时视频。
2118 0
|
存储 缓存 JavaScript
不要过度封装!封装一个最简单的Axios!
前言 axios 是目前最优秀的 HTTP 请求库之一,虽然 axios 已经封装的非常好了,我们可以直接拿过来用。但是在实际的项目中,我们可能还需要对 axios 在封装一下,以便我们更好的管理项目和各个借口。 但是,目前网上有特别多的针对于 axios 在项目中的封装。不得不说,很多大佬封装得非常全面,方方面面都考虑到了。但是我们的每个真的都需要那些封装吗?显然不是的,网上的很多封装其实都显得有点过度封装了! 本篇文章实现最简单 Axios 封装,让小伙伴们扩展起来容易一些。
6035 0
不要过度封装!封装一个最简单的Axios!
|
前端开发
elementui解决el-dialog不清空内容的问题,el-dialog关闭时销毁子组件
elementui解决el-dialog不清空内容的问题,el-dialog关闭时销毁子组件
|
存储 JavaScript 前端开发
架构-单一代码库-monorepo-pnpm-workspace:基本使用
架构-单一代码库-monorepo-pnpm-workspace:基本使用
1397 0
|
9月前
|
JavaScript 前端开发 UED
Vue 手风琴实现的三种常用方式及长尾关键词解析
手风琴效果是Vue开发中常见的交互组件,可节省页面空间、提升用户体验。本文介绍三种实现方式:1) 原生Vue结合数据绑定与CSS动画;2) 使用Element UI等组件库快速构建;3) 自定义指令操作DOM实现独特效果。每种方式适用于不同场景,可根据项目需求选择。示例包括产品特性页、后台菜单及FAQ展示,灵活满足多样需求。附代码示例与资源链接,助你高效实现手风琴功能。
474 10
Vue3使用hook封装常见的几种异步请求函数场景,让开发更加丝滑🚀🚀🚀
Vue3使用hook封装常见的几种异步请求函数场景,让开发更加丝滑🚀🚀🚀
|
JavaScript API
【vue3】写hook这几天,治好了我不会组件封装的弱点。
【vue3】写hook这几天,治好了我不会组件封装的弱点。
|
前端开发 测试技术 API
我同学不知道UnoCSS是什么,我教他用之后效率直接倍增
原子化 CSS 是一种 CSS 的架构方式,它倾向于小巧且用途单一的 class,并且会以视觉效果进行命名。可以将原子化的 CSS 框架理解为这类 CSS 的统称
1582 5
Vue3拖拽插件(vuedraggable@next)
vuedraggable 是一款 Vue2 拖拽插件,可轻松实现列表项的拖拽排序与交互。通过简单配置,即可在不同区域间拖动元素并实现数据同步。支持多种事件监听和自定义样式。
1886 2
Vue3拖拽插件(vuedraggable@next)
|
前端开发 JavaScript
tailwindcss保姆级教程(完整版带解析)
【8月更文挑战第2天】
1551 6