useAsync 的使用
直接查看具体使用方式
<script setup lang="ts">
const {loading, data, error, run, cancel} = useAsync(api)
/*
分析:
loading 加载状态
data 成功结果
error 失败结果
run 发出请求
cancel 取消请求
参数:
api 我们的异步请求
*/
onMounted(() => {
// requerstParams 请求参数
/* requestConfig AxiosRequestConfig额外的配置, 或者一些自定义的配置
在axios的响应拦截可以获取到配置信息,自定义响应结果
instance.interceptors.response.use((response) => {
console.log(response.config)
})
*/
run(requerstParams, requestConfig)
})
</script>
useAsync 具体代码实现
const useAsync = <T = unknown>(
api: (params: Recordable, config: RequestConfig) => Promise<T>
) => {
const { initState, delay = 0 } = config
const result = reactive<State<T>>({
data: initState ? (initState as T) : undefined,
loading: false,
error: undefined,
})
const cancel = ref<undefined | (() => void)>(undefined)
const run = async (pms: Recordable = {}, conf: Recordable = {}) => {
result.loading = true
try {
const data = await api(pms), {
cancelToken: new CancelToken(function executor(c) {
cancel.value = c
}),
...conf,
})
result.data = data as UnwrapRef<T>
result.error = undefined
return data
} catch (err) {
result.error = err
} finally {
result.loading = false
}
}
return {
...toRefs(result),
cancel,
run,
}
}
到此useAsync的封装结束。
useAsync 的扩展 useQueryWithPagination
需求分析:相信大家用element-plus 以及 ant design vue不少,我个人比较喜欢用后者,一起来聊聊 Table 组件。想必我们使用table组件难免会遇到切换页码发出请求情况,接下来我们基于useAsync去封装一个,不过在此之前,我们还是先来看看他的使用。
useQueryWithPagination 的使用
<script setup lang="ts">
// 搜索参数
const filterParams = reactive({
name: 'zhangsan',
age: 20
})
const {data, loading,run, reload, onPageChange} = useQueryWithPagination(api)
// 搜索
const onFilterSearch = () => {
run(filterParams)
}
// 重刷
const onRelod = () => reload()
</script>
<template>
<a-table :loading="loading" :data-source="data" columns="..." @change="onPageChange"/>
</template>
useQueryWithPagination 具体代码实现
export const useQueryWithPagination = <T>(
api: (params: Recordable, config: RequestConfig) => Promise<T>,
params?: Recordable,
config: Config = {},
) => {
const { current = 1, pageSize = 10 } = config
const pagination = reactive<PaginationType>({
current: current,
pageSize: pageSize,
total: 0,
})
const { data, loading, error, run, cancel } = useAsync(api)
const reload = () =>
run({
...toRaw(params),
page: pagination.current,
size: pagination.pageSize,
})
const onPageChange = (value: PaginationType) => {
Object.assign(pagination, value)
}
watchEffect((invalid) => {
run({
...params,
size: pagination.pageSize,
page: pagination.current,
})
invalid(() => {
cancel.value?.()
})
})
return {
loading,
error,
pagination,
run,
reload,
data: data as UnwrapRef<T>,
onPageChange,
}
}
重点分析watchEffect
watchEffect((invalid) => {
// 组件挂载之后调用,即onMounted
run({
...params,
size: pagination.pageSize,
page: pagination.current,
})
// 依赖状态更新或者组件卸载之后调用,即onUpdated或者onUnmountd
invalid(() => {
// 取消请求
cancel.value?.()
})
})
学过的React的同学,完全可以把它当作useEffect使用。
源码
这个源码和示例有些出入,主要是添加一些配置值,整体思路差不多。
总结
本文只是介绍了两种hook async的封装方法,但是通常情况下还有一种就是我们进入详情页的时候会立即调用接口请求详情信息,所以你完全可以基于useAsync进行扩展,由于实现简单,我就不哆嗦了,就是加个onMounted的事情,具体实现可以查看源码。
如果喜欢文本,欢迎大家收藏点赞。