有了useAsyncState可以不用手动声明loading表示请求状态了
前端在发起网络请求的时候往往要做这样几件事情:声明一个loading变量表示请求状态,发起请求时设置为true,结束请求时设置为false;处理网络请求的异常情况;某些场景还需要重置请求结果。对于开发同学当然是越省事儿越好,useAsyncState刚好可以帮我们解决问题。今天就来学习useAsyncState的使用和源码,学习完您可以用到自己的vue3项目中。
简介
useAsyncState提供了响应式的异步状态。
示例
看一下官方文档给出的示例代码:
<script setup lang="ts">
import axios from 'axios'
import YAML from 'js-yaml'
import { useAsyncState } from '@vueuse/core'
const { isLoading, state, isReady, execute } = useAsyncState(
(args) => {
const id = args?.id || 1
return axios.get(`https://jsonplaceholder.typicode.com/todos/${id}`).then(t => t.data)
},
{},
{
delay: 2000,
resetOnExecute: false,
},
)
</script>
<template>
<div>
<note>Ready: {{ isReady.toString() }}</note>
<note>Loading: {{ isLoading.toString() }}</note>
<pre lang="json" class="ml-2">{{ YAML.dump(state) }}</pre>
<button @click="execute(2000, { id: 2 })">
Execute
</button>
</div>
</template>
如上代码引入了useAsyncState,并执行useAsyncState从返回结果中解构出isLoading, state, isReady, execute。调用useAsyncState的参数分别为能够返回promise的函数,初始state为一个空对象,可选的options对象的两个属性delay为延迟执行时间,resetOnExecute表示执行网络请求之前是否重置state。
代码执行效果如下图所示,您可以访问官网或者写demo自己试一下:
点击Execute后的效果如下图:
源码
我们预览一下useAsyncState方法体:
参数说明
function useAsyncState<Data, Shallow extends boolean = true>(
promise: Promise<Data> | ((...args: any[]) => Promise<Data>),
initialState: Data,
options?: AsyncStateOptions<Shallow>,
)
promise 为一个Promise或者返回Promise的方法;initialState用于重置state;options为可选的,有如下几个选项:delay为执行promise的延迟时间,onError为执行promise时捕获到错误时的回调,resetOnExecute如果为true则在执行promise之前重置state;shallow为true则使用vue的shallowRef创建state,否则使用Ref。AsyncStateOptions的定义如下:
export interface AsyncStateOptions<Shallow extends boolean> {
delay?: number
immediate?: boolean
onError?: (e: unknown) => void
resetOnExecute?: boolean
shallow?: Shallow
}
state初始化
const state = shallow ? shallowRef(initialState) : ref(initialState)
const isReady = ref(false)
const isLoading = ref(false)
const error = ref<unknown | undefined>(undefined)
根据initialState创建出的Ref赋值给state;isReady初始化为false, isLoading也初始化为false,error初始化为undefined。
execute方法定义
async function execute(delay = 0, ...args: any[]) {
if (resetOnExecute)
state.value = initialState
error.value = undefined
isReady.value = false
isLoading.value = true
if (delay > 0)
await promiseTimeout(delay)
const _promise = typeof promise === 'function'
? promise(...args)
: promise
try {
const data = await _promise
state.value = data
isReady.value = true
}
catch (e) {
error.value = e
onError(e)
}
finally {
isLoading.value = false
}
return state.value as Data
}
execute方法的第一个参数为delay表示promise延迟执行的时间,其余的参数用args接收。如果resetOnExecute为真值,则初始化state。接着给error、isReady和isLoading赋予对应的值。如果delay大于0则执行一段延时。判断上级作用域的promise参数是函数还是promise对象,如果是函数则先执行函数,函数的执行结果为一个promise。接着在try语句块中执行promise,根据promise的执行结果修改state的值,然后修改isReady的值为true。如果发生了异常则给error赋值并触发onError回调。在finally语句块中修改isLoading的值为false。最后返回state。下图描述了execute的执行过程:
立即执行execute
if (immediate)
execute(delay)
如果options的immediate选项为true则立即执行execute方法。
返回状态
return {
state: state as Shallow extends true ? Ref<Data> : Ref<UnwrapRef<Data>>,
isReady,
isLoading,
error,
execute,
}
注意在返回对应的响应式值的时候也返回了execute方法。
总结
useAsyncState对异步请求进行了封装。对于loading状态、异常(error)等都定义为响应式变量和包装后的请求方法一起暴露给开发者。整个useAsyncState的核心又在于execute方法的定义。useAsyncState主要用到的vue3 API是shallowRef和ref。
转载自:https://juejin.cn/post/7111130096773103623