Vue 3 组合式函数:可复用 useRequest 封装请求与 loading
test12026-09-110 次阅读
每个页面都在手写 loading 和 error 太重复了
在 Vue 3 项目里,几乎每个需要拉数据的组件都要维护 loading、error、data 三个 ref,再加上 try/catch 和 onUnmounted 清理。这些逻辑高度相似,却散落在几十个文件里,一改就要全局搜。组合式函数(composable)正是为此而生:把请求生命周期收敛成一个可复用的函数。
写一个最小可用的 useRequest
下面这个实现关注三件事:请求进行时 loading 为 true;组件卸载后用 token 阻止旧请求回调污染新状态;异常统一收敛到 error。
import { ref, onUnmounted } from 'vue'
export function useRequest<T>(fn: () => Promise<T>) {
const data = ref<T | null>(null)
const loading = ref(false)
const error = ref<unknown>(null)
let token = 0
async function run() {
const my = ++token
loading.value = true
error.value = null
try {
data.value = await fn()
} catch (e) {
error.value = e
} finally {
if (my === token) loading.value = false
}
}
onUnmounted(() => { token++ })
return { data, loading, error, run }
}
在组件里用起来
调用方只关心 run 和三个状态,不用再碰 try/catch。token 机制保证快速切换路由时,先发出的慢请求回来也不会覆盖后一个页面的数据。
<script setup lang="ts">
import { useRequest } from '@/composables/useRequest'
import { fetchProfile } from '@/api/user'
const { data, loading, error, run } = useRequest(fetchProfile)
run()
</script>
<template>
<p v-if="loading">加载中</p>
<p v-else-if="error">出错了</p>
<p v-else>{{ data?.name }}</p>
</template>
继续增强而不破坏调用方
- 加 immediate 参数:传入即自动 run,省掉手动调用。
- 加 debounce:把 run 包一层防抖,输入框搜索场景直接复用。
- 加 refresh 依赖:用 watch 监听参数变化时重跑,列表筛选很合适。
关键点在于:组合式函数返回的是普通 ref,调用方拿到的是响应式状态,模板和逻辑都不需要为抽离付出额外成本。这正是 Composition API 相比 mixin 最干净的地方——没有命名冲突,类型也能推导。
T
test1
文章作者
每个页面都在手写 loading 和 error 太重复了 在 Vue 3 项目里,几乎每个需要拉数据的组件都要维护...
- 分类
- 技术
- 发布时间
- 2026-09-11
- 字数
- 约 1532 字
- 阅读
- 0 次
