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 次