一行代码搞定Vue3异步请求:vue3-request让状态管理从地狱到天堂

一行代码搞定Vue3异步请求:vue3-request让状态管理从地狱到天堂

用了3年Vue3+TS,终于找到了异步请求管理的完美解决方案!再也不用写那些重复的loading、error代码了...

😫 程序员的日常崩溃现场

作为一个Vue3+TypeScript的深度用户,我相信你一定写过这样的代码:

ts 复制代码
<script setup lang="ts">
import { axios } from 'axios'
// 每个接口都要写这一套,真的很烦... 😤
const loading = ref<boolean>(false)
const error = ref<Error | null>(null)
const data = ref<UserInfo | null>(null)

interface UserInfo {
  id: number
  name: string
  email: string
}

const controller = new AbortController()

const getUserInfo = async () => {
  loading.value = true
  error.value = null
  
  try {
    const res = await axios.get('/api/userInfo', {
      signal: controller.signal
    })
    data.value = res
  } catch (err) {
    error.value = err
  } finally {
    loading.value = false
  }
}

onMounted(() => {
  getUserInfo()
})

onUnmounted(() => {
  controller.abort() // 还得记得清理,漏了就内存泄漏
})
</script>

每次写这种代码我都想吐槽:

  • 🤮 样板代码太多:每个请求都要重复这些状态管理
  • 😵 类型定义繁琐:loading、error、data 都要手动定义类型
  • 🐛 容易出bug:忘记清理AbortController,忘记处理error
  • 🔄 重复劳动:复制粘贴改改改,程序员的尊严何在?

停止这种痛苦吧! 让我们看看 vue3-request 如何用一行代码解决所有问题。

✨ vue3-request:异步请求的终极解决方案

🎯 核心亮点

  • 🚀 一行代码搞定:loading、error、data 状态自动管理
  • 💎 完美 TypeScript:全类型推导,告别 any
  • 智能请求中止:自动生成 AbortSignal,避免内存泄漏
  • 💾 内置缓存 & SWR:极致性能优化
  • 🔄 错误重试:网络异常自动重试
  • 🎭 插件化架构:满足复杂业务场景

🚀 5秒上手:看看威力有多大

安装

bash 复制代码
# 我推荐用 pnpm,速度快
pnpm add vue3-request

# 当然 npm/yarn 也行
npm install vue3-request
yarn add vue3-request

基础使用:从 50 行代码到 1 行代码

ts 复制代码
<script setup lang="ts">
import { axios } from 'axios'
import { useRequest } from 'vue3-request'

interface UserInfo {
  id: number
  name: string
  email: string
}

const getUserInfo = async (): Promise<UserInfo> => {
  return await axios.get('/api/user', {
    signal: signal.value  // 🔥 自动注入 AbortSignal
  })
}

// ✨ 一行代码解决所有状态管理!
const { 
  data,     // Ref<UserInfo | undefined> 完美类型推导
  loading,  // Ref<boolean>
  error,    // Ref<Error | undefined>
  signal,   // Ref<AbortSignal> 自动生成
  refresh,  // () => void
  abort     // () => void
} = useRequest(getUserInfo)
</script>

对比效果:

  • ❌ 传统方式:50+ 行代码,手动状态管理
  • ✅ vue3-request:1 行代码,自动搞定一切

✨ 手动触发 + TypeScript 参数类型检查

typescript 复制代码
interface SearchParams {
  keyword: string
  page: number
}

const searchUsers = async (params: SearchParams): Promise<User[]> => {
  return await api.search(params)
}

const { run, runAsync, data, loading } = useRequest(searchUsers, {
  manual: true // 手动触发
})

// TypeScript 会检查参数类型,传错了立马报错
run({ keyword: 'vue', page: 1 }) // ✅ 正确
run({ name: 'vue' }) // ❌ TypeScript 报错,参数类型不匹配

// 异步调用也有完整的类型支持
const handleSearch = async () => {
  try {
    const result = await runAsync({ keyword: 'react', page: 1 })
    // result 的类型是 User[],智能提示完美
    console.log(result[0].name)
  } catch (error) {
    console.error('搜索失败:', error)
  }
}

💾 缓存 + SWR,性能优化神器

typescript 复制代码
interface ApiResponse<T> {
  code: number
  data: T
  message: string
}

const getUserList = async (): Promise<ApiResponse<User[]>> => {
  // 模拟真实项目的接口调用
  return axios.get<ApiResponse<User[]>>('/api/users')
}

const { data, loading } = useRequest(getUserList, {
  cacheKey: 'user-list',           // 缓存key
  staleTime: 8000,                 // 8秒内不重复请求
  cacheTime: 10 * 60 * 1000,       // 10分钟后清除缓存
})

// 用户体验:
// 1. 首次访问:显示loading,获取数据
// 2. 组件重新加载:立即显示缓存数据,后台静默更新
// 3. 多个组件共享同一个缓存,请求只会发一次!

🛡️ 请求中止,妈妈再也不用担心内存泄漏

typescript 复制代码
const searchAPI = async (keyword: string): Promise<SearchResult[]> => {
  // signal 自动提供,不用手动创建 AbortController
  const response = await fetch(`/api/search?q=${keyword}`, {
    signal: signal.value
  })
  return response.json()
}

// abort方法可手动直接调用中止请求
const { signal, abort, run } = useRequest(searchAPI, { manual: true })

// 搜索框输入,自动取消上一次请求
const handleSearch = (keyword: string) => {
  run(keyword) //前置请求中止: 内部自动调用abort方法中止前一次未完成的请求,发起新请求
}

// 组件销毁时自动 abort,无需手动处理

🔁 轮询监控

typescript 复制代码
interface SystemStatus {
  cpu: number
  memory: number
  disk: number
  timestamp: number
}

const getSystemStatus = async (): Promise<SystemStatus> => {
  const response = await fetch('/api/system/status')
  return response.json()
}

const { data: systemStatus, error } = useRequest(getSystemStatus, {
  pollingInterval: 5000,         // 5秒轮询一次
  pollingWhenHidden: false,      // 页面隐藏时停止轮询
  refreshOnWindowFocus: true,    // 窗口聚焦时刷新
})

🧩 插件系统

ts 复制代码
<script setup lang="ts">
import { useRequest, definePlugin } from 'vue3-request'

// 🎯 自定义日志插件
const logPlugin = definePlugin<UserInfo, [], { logLevel: string }>(
  (requestInstance, options) => ({
    onBefore: () => {
      console.log(`[${options.logLevel}] 🚀 请求开始`)
    },
    onSuccess: (data) => {
      console.log(`[${options.logLevel}] ✅ 请求成功:`, data)
    },
    onError: (error) => {
      console.error(`[${options.logLevel}] ❌ 请求失败:`, error.message)
    }
  })
)

// 🎯 消息提示插件
const messagePlugin = definePlugin<UserInfo, []>(
  (requestInstance) => ({
    onSuccess: () => {
      // 假设使用 Element Plus
      ElMessage.success('数据加载成功')
    },
    onError: (error) => {
      ElMessage.error(`加载失败: ${error.message}`)
    }
  })
)

// 🚀 使用多个插件
const { data, loading, error } = useRequest(
  fetchUser,
  { 
    logLevel: 'info',  // 插件配置,完美的类型提示
    refreshOnWindowFocus: true
  },
  [logPlugin, messagePlugin]  // 插件组合
)
</script>

高级用法(生产环境推荐)

typescript 复制代码
// hooks/useUserList.ts - 抽取成自定义Hook
import { useRequest } from 'vue3-request'
import type { Ref } from 'vue'

interface UserListOptions {
  autoRefresh?: boolean
  cacheEnabled?: boolean
}

export function useUserList(options: UserListOptions = {}) {
  const { autoRefresh = true, cacheEnabled = true } = options
  
  return useRequest(fetchUsers, {
    // 缓存配置
    ...(cacheEnabled && {
      cacheKey: 'user-list',
      staleTime: 5 * 60 * 1000, // 保鲜5分钟
      cacheTime: 10 * 60 * 1000, // 缓存10分钟
    }),
    
    // 自动刷新
    ...(autoRefresh && {
      pollingInterval: 30 * 1000,      // 30秒轮询一次
      refreshOnWindowFocus: true,       // 窗口聚焦刷新
    }),
    
    // 错误重试
    retryCount: 3,
    retryInterval: 1000,
    
    // 生命周期钩子
    onSuccess: (data) => {
      console.log('用户列表加载成功:', data.length)
    },
    onError: (error) => {
      console.error('用户列表加载失败:', error)
      // 这里可以接入错误监控
    }
  })
}

📊 性能对比:数据说话

功能特性 传统方式 vue3-request
代码量 50+ 行 1 行
类型安全 手动维护 自动推导
请求中止 复杂实现 自动管理
缓存策略 需要造轮子 内置 SWR
错误重试 手写逻辑 配置即用
防抖节流 额外依赖 内置支持
轮询功能 复杂实现 一行配置

为什么选择 vue3-request?

🚀 开发效率飞升

typescript 复制代码
// 对比:实现一个带缓存、重试、防抖的搜索功能

// ❌ 传统方式:100+ 行代码
// ✅ vue3-request:5 行代码

const { data, loading, run } = useRequest(searchApi, {
  manual: true,
  debounceWait: 300,
  cacheKey: 'search',
  errorRetryCount: 3
})

💭 总结:为什么你应该试试 vue3-request?

说实话,用了 vue3-request 之后,我再也回不去手写那些状态管理了。它让我的代码:

  1. 更干净 📝:告别样板代码,专注业务逻辑
  2. 更安全 🛡️:TypeScript 类型安全 + 自动请求清理
  3. 更高效 ⚡:内置缓存、防抖、重试等优化策略
  4. 更可靠 🔒:经过实际项目验证的最佳实践

如果你也在用 Vue3 + TypeScript 开发项目,强烈建议试试 vue3-request。它不是银弹,但绝对能让你的开发体验提升一个档次!

相关链接:

GitHub地址 github.com/Flame-00/vu... 点个Star吧!

文档地址 Flame-00.github.io/vue3-reques...

相关推荐
不爱说话郭德纲2 小时前
👩‍💼产品姐一句小优化,让我给上百个列表加上一个动态实时计算高度的方法😿😿
前端·vue.js·性能优化
知识分享小能手2 小时前
React学习教程,从入门到精通, React教程:构建你的第一个 React 应用(1)
前端·javascript·vue.js·学习·react.js·ajax·前端框架
李剑一2 小时前
别乱封装,你看出事儿了吧...
前端·vue.js
gongzemin2 小时前
Vue 项目权限管理 路由 按钮权限
前端·vue.js
FAIRY_STARS3 小时前
VUE3大屏自适应布局
vue.js
GISBox3 小时前
GIS新手入门首选!GISBox中文界面+一键安装,零依赖轻松搞定三维数据发布
vue.js·json·gis
FliPPeDround4 小时前
🚀 定义即路由:definePage宏如何让uni-app路由配置原地起飞?
前端·vue.js·uni-app
做你的猫4 小时前
深入剖析:基于Vue 3与Three.js的3D知识图谱实现与优化
前端·javascript·vue.js
做你的猫4 小时前
深入剖析:基于Vue 3的高性能AI聊天组件设计与实现
前端·javascript·vue.js