将异步方法的逻辑封装进hook中
ts
import { ref } from 'vue'
type AsyncMethod<R, P extends unknown[]> = (...args: P) => Promise<R>
interface Options<R, P> {
/**
* 是否手动请求. 默认:false
*
* false表示asyncMethod方法会在组件created时自动调用, true表示asyncMethod方法不会在组件created时自动调用,必须手动调用run方法才会真正执行
*/
manual: boolean
/**
* 当manual不为false时,会使用initData作为参数自动执行run方法
*/
initData?: P
/**
* asyncMethod 执行成功之后的回调方法
*
* @param {R} ret asyncMethod的返回值
*/
onSuccess?: (ret: R) => void
/**
* asyncMethod 执行异常时的回调方法
*
* @param {unknown} err 异常对象
*
*/
onError?: (err: unknown) => void
/**
* 无论asyncMethod方法执行成功或失败都会调用的回调方法
*/
onFinally?: () => void
}
export function useAsync<R = unknown, P extends unknown[] = any>(
asyncMethod: AsyncMethod<R, P>,
options = {} as Options<R, P>
) {
const { manual = false, initData, onSuccess, onError, onFinally } = options
const loading = ref<boolean>(false)
const data = ref<R>()
const error = ref<unknown>()
async function run(...args: P): Promise<R | undefined> {
loading.value = true
try {
const ret = await asyncMethod(...args)
data.value = ret
onSuccess && onSuccess(ret)
return ret
} catch (err) {
onError && onError(err)
error.value = err
} finally {
loading.value = false
onFinally && onFinally()
}
}
if (!manual) {
if (initData) {
run(...initData)
} else {
// @ts-ignore
run()
}
}
return { loading, data, error, run }
}