vue3中超赞的请求数据管理方案vue-query !
2025-05-03 08:43 阅读(60)

在前端开发的数据请求与处理中,我们可能经常会写出这样的请求处理代码:


// 传统数据获取方式示例
const loading = ref(false)
const error = ref(null)
const data = ref([])

const fetchData = async () => {
  try {
    loading.value = true
    const res = await axios.get('/api/data')
    data.value = res.data
  } catch (err) {
    error.value = err
  } finally {
    loading.value = false
  }
}
// 需要手动管理加载状态、错误处理、缓存...

代码并没有问题,只是这种固定模式的代码在很多场景下写起来过于繁琐,vue-query 完美的解决了这个问题。

vue-query 是什么?

@tanstack/vue-query 是流行的 React Query 在 Vue 上的实现版本。它不是网络请求库的替代品(如 axios 或 fetch),而是对网络请求结果的 缓存、状态管理、自动刷新、重试机制 等进行了统一封装。它具有以下优势:


自动缓存和数据同步

请求失败自动重试

页面聚焦自动重新请求数据

请求状态自动管理(加载中、错误、成功)

支持分页、无限加载等高级功能

代码更简洁、逻辑更清晰


借助 Vue Query,我们可以专注于“数据如何使用”,而不用操心“数据从哪里来、何时来、状态如何”等细节问题,从而大幅提升前端开发的体验与效率。

安装与初始化

npm install @tanstack/vue-query

安装依赖后,在 main.ts 或 main.js 中配置 VueQuery即可使用


核心 API 详解与实战

useQuery-数据请求

useQuery是获取数据的核心方法

<script setup>
import { useQuery } from '@tanstack/vue-query'

const { data, isLoading, isError } = useQuery({
  queryKey: ['todos'], // 唯一缓存标识
  queryFn: () => axios.get('/api/todos').then(res => res.data)
})
</script>

<template>
  <div v-if="isLoading">加载中...</div>
  <div v-else-if="isError">出错了!</div>
  <ul v-else>
    <li v-for="todo in data" :key="todo.id">{{ todo.title }}</li>
  </ul>
</template>

上述代码使用 @tanstack/vue-query 实现了异步获取待办列表(todos)数据,它的核心参数如下:


queryKey: ['todos']

每个查询都需要一个唯一的 key,用于缓存标识(同样的 key 会共享缓存)。

queryFn: () => axios.get(...)

实际的数据请求函数,返回一个 Promise,结果会被自动缓存。

解构的 data, isLoading, isError:data:接口返回的数据(已自动解析)、isLoading:是否处于加载中状态、isError:是否请求失败


基于useQuery的解构属性,我们可以实现以下高级功能:


自动刷新和缓存时间

useQuery({
  queryKey: ['posts'],
  queryFn: fetchPosts,
  refetchOnWindowFocus: true, // 页面切回自动刷新
  staleTime: 1000 * 60 * 5     // 数据 5 分钟内不重新获取
})

条件查询

useQuery({
  queryKey: ['user', userId],
  queryFn: () => fetchUser(userId),
  enabled: !!userId   // userId 存在才执行
})

手动刷新

const { refetch } = useQuery({
  queryKey: ['posts'],
  queryFn: fetchPosts
})

refetch() // 手动重新获取数据

取消请求

const { data,cancel } = useQuery({
  queryKey: ['todos'],
  queryFn: ()=>{},
});

// 取消请求
const cancelRequest = () => {
  cancel();
};

数据共享

使用相同的 key,我们可以在其他组件共享数据

<script setup>
import { useQuery } from '@tanstack/vue-query'

const { data } = useQuery({ queryKey: ['todos'] }) // 使用相同的 key,共享数据
</script>

<template>
  <div>共有 {{ data?.length || 0 }} 个待办</div>
</template>

useQuery 是为了 获取数据 设计的,它会根据查询键(queryKey)缓存数据,并且会自动执行并更新状态。使用 POST 请求时提交或修改数据时,我们通常使用useMutation。


请求合并


useQuery 默认会在短时间内合并对同一个 queryKey 的多个请求。这意味着,若有多个组件请求相同的数据,vue-query 会合并请求并且只发出一次请求。这有助于避免冗余的请求。

使用 useMutation 执行副作用操作

useMutation 是 React Query 用于执行 创建、修改、删除等副作用操作(例如 POST、PUT、DELETE 请求)的 Hook。它与 useQuery 不同,后者主要用于获取数据和缓存。useMutation 专注于发起请求、更新数据或提交数据时的状态管理。

import { useMutation } from '@tanstack/vue-query'
import axios from 'axios'

const { mutate, isLoading, isError, data, error, isSuccess } = useMutation({
  mutationFn: (newTodo) => axios.post('/api/todos', newTodo),
  onSuccess: (data) => {
    console.log('提交成功', data)
  },
  onError: (error) => {
    console.log('提交失败', error)
  }
})

// 调用方式
mutate({ title: '学习Vue-Query', completed: false })

mutate 是触发 mutation 操作的函数,传入的参数会被传递到 mutationFn 中,启动数据提交操作。

const { mutate } = useMutation({
  mutationFn: (newTodo) => axios.post('/api/todos', newTodo)
})

// 调用 mutate 提交新任务
mutate({ title: '新的任务', completed: false })

data 是 mutation 成功后返回的数据。你可以通过它来获取 API 返回的结果,并在 UI 中展示。


console.log('任务提交成功:', data)

reset 用于重置 mutation 的状态。通常在表单提交成功后,或者用户手动触发重置时使用。


const { reset } = useMutation({
  mutationFn: (newTodo) => axios.post('/api/todos', newTodo)
})

// 提交成功后重置状态
reset()

queryClient 用法

queryClient 是 vue-query 的核心对象,它用于全局管理缓存、请求重试、数据失效等。可以通过 queryClient 来执行诸如缓存清除、查询失效、手动触发查询等操作。


手动触发查询

import { useQueryClient } from '@tanstack/vue-query';

const queryClient = useQueryClient();
const { data } = useQuery(['todos'], fetchTodos);

// 通过 queryClient 手动触发查询
queryClient.refetchQueries(['todos']);

失效查询(Invalidate) invalidateQueries 用于标记某个查询为失效,之后会重新请求数据。


// 手动失效某个查询
queryClient.invalidateQueries(['todos']);

移除缓存(Remove Query Cache) 如果你希望从缓存中删除某个查询的数据,可以使用 removeQueries。


queryClient.removeQueries(['todos']);

清空缓存(Clear Cache) clear() 会清除所有缓存的查询。


queryClient.clear();

分页和无限加载

useQuery 支持分页和无限滚动等高级功能。通过 getNextPage 和 getPreviousPage 可以管理分页请求,或者用 useInfiniteQuery 实现无限加载。

const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery(
  'todos',
  fetchTodos, {
    getNextPageParam: (lastPage, allPages) => lastPage.nextCursor,
  }
);

if (isFetchingNextPage) {
  return '加载更多...';
}

return (
  <>
    {data.pages.map((page) =>
      page.todos.map((todo) => <Todo key={todo.id} todo={todo} />)
    )}
    {hasNextPage && <button onClick={() => fetchNextPage()}>加载更多</button>}
  </>
);

useInfiniteQuery 用于处理分页请求,getNextPageParam 用于指定如何获取下一页的参数


https://www.zuocode.com