vue3中的hooks其实是函数的写法,就是把一些单独功能的js代码抽离出来,放到单独的js文件中。最近在用vue3+ts开发项目,在实际的开发中需要做一些重复的事情,常常被 loading 状态的管理、请求的节流防抖、接口数据的缓存、分页等这些重复的实现所困惑。每当开启一个新项目时,我们都得手动去处理以上这些问题,这将是一个重复性的工作,而且还得确保团队的一致。封装useRequest:管理接口的状态。
封装的useRequest实现了以下的功能:
- 防抖和节流
- 轮询
- loading状态
- 手动请求和自动请求
useRequest.ts
import { ref, computed } from 'vue'
import { delay, debounce, throttle } from 'lodash'
import type { IUseRequestOption, IUseRequestRequest } from './../type'
// 引入返回值类型
import type { YWZResponse } from '@/service/index'
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>()
// 警告
if (option.throttle && option.debounce) {
console.warn(
'[ywz warn]: useRequest的配置项中的throttle和debounce均为true,请选择一个,否则这样默认使用防抖',
)
}
// 调用方法
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()
// 计算最终使用的函数
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 {
run: runComputed.value.run,
loading,
data,
runParams: runComputed.value.runParams,
}
}
export default useRequest
type/index.ts
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>
}
export interface IWhyRequest<T> {
code: number
data: T
}
request/index.ts
import useRequest from './src/useRequest'
export { useRequest }