Code前端首页关于Code前端联系我们

vue2项目里怎么用vue-query?从基础到实践的常见问题解答

terry 1天前 阅读数 16 #Vue
文章标签 query

做vue2项目时,每次写接口请求都要手动管加载状态、缓存、重复请求,是不是头大?要是有个工具能自动搞定这些,代码还简洁,那该多爽!vue-query就是干这个的,但不少同学在vue2里用它时,总会碰到“咋安装?咋发请求?分页咋处理?”这些问题,今天就从基础到实践,把vue2 + vue-query的常见问题拆明白,看完你也能轻松用它搞定数据层!

vue-query是啥?vue2项目为啥要考虑用它?

vue-query是专门管理数据请求与状态的工具库,不管是查询接口(query)还是增删改操作(mutation),它都能自动处理缓存、重复请求拦截、加载状态维护、后台数据同步这些“脏活”。

那vue2项目里手动写请求有多麻烦?举个例子:用axios调接口时,得自己定义loading变量,请求前设为true、成功/失败后设为false;还要手动把响应数据存到data里;遇到重复请求,得写拦截器去重;想做缓存,还得用localStorage或vuex存数据……每次新增接口,这些重复代码都得写一遍,又累又容易出错。

而vue-query把这些事儿全封装了:发请求时自动管理loading/error状态,相同标识的请求自动缓存,页面切回来时自动刷新“过期”数据,甚至连请求重试、分页缓存都内置好了,对vue2老项目来说,不用重构整个架构,只在数据请求层替换,就能让代码量少一大半,维护性直接起飞。

vue2里咋安装和初始化vue-query?

首先得选对版本!因为vue-query现在叫@tanstack/vue-queryvue2要装v3版本(v4以上主要支持vue3 + Composition API,vue2用v3更稳),命令行执行:

npm install @tanstack/vue-query@3

安装完后,要在main.js里全局注册插件,代码示例:

import Vue from 'vue'
import { VueQueryPlugin } from '@tanstack/vue-query'
Vue.use(VueQueryPlugin, {
  queryClientConfig: {
    defaultOptions: {
      queries: {
        staleTime: 5 * 60 * 1000, // 5分钟内数据视为“新鲜”,不自动请求
        cacheTime: 10 * 60 * 1000, // 缓存数据保留10分钟
        retry: 3, // 请求失败自动重试3次
      },
    },
  },
})

这里staleTimecacheTime要注意区别:staleTime是数据的“新鲜期”,过期后下次访问会后台静默更新;cacheTime是数据的“缓存期”,过期后会被垃圾回收,下次得重新请求,根据项目需求调整这两个值,能平衡性能和数据新鲜度。

发第一个请求,vue-query基本流程是啥?

useQuery就能发查询请求,核心是两个参数:queryKey(请求的唯一标识,一般用数组,方便传参)和queryFn(实际发请求的函数)。

举个“获取文章列表”的例子(假设接口是/api/articles):

<template>
  <div>
    <div v-if="isLoading">加载中...</div>
    <div v-else-if="isError">{{ error.message }}</div>
    <div v-else>
      <ul>
        <li v-for="item in data" :key="item.id">{{ item.title }}</li>
      </ul>
    </div>
  </div>
</template>
<script>
import { useQuery } from '@tanstack/vue-query'
import axios from 'axios'
export default {
  name: 'ArticleList',
  setup() {
    // queryKey用数组,方便后续加参数(比如分页)
    const queryKey = ['articles']
    // queryFn返回Promise,封装接口请求
    const queryFn = () => axios.get('/api/articles').then(res => res.data)
    // 调用useQuery,拿到数据和状态
    const { data, isLoading, isError, error } = useQuery(queryKey, queryFn)
    return { data, isLoading, isError, error }
  },
}
</script>

这里queryKey必须唯一!如果两个组件用了一样的queryKey,vue-query会自动复用缓存,避免重复请求,比如另一个组件也查文章列表,用相同的['articles'],就会直接读缓存,不用再调接口。

列表分页场景,vue-query咋处理?

分页时,请求参数一般有pagesize,这时候把参数放到queryKey里,vue-query就能自动识别参数变化、触发重新请求,用keepPreviousData能让分页切换时,旧数据不消失,用户体验更丝滑。

看例子(假设接口是/api/articles?page=xxx&size=xxx):

<template>
  <div>
    <button @click="page--" :disabled="page === 1">上一页</button>
    <button @click="page++">下一页</button>
    <div v-if="isLoading">加载中...</div>
    <ul v-else>
      <li v-for="item in data" :key="item.id">{{ item.title }}</li>
    </ul>
    <div v-if="isPreviousData">正在加载新页,暂时显示上一页内容...</div>
  </div>
</template>
<script>
import { useQuery } from '@tanstack/vue-query'
import axios from 'axios'
import { ref } from 'vue'
export default {
  name: 'ArticlePage',
  setup() {
    const page = ref(1)
    const size = ref(10)
    // queryKey包含page和size,参数变化时自动重新请求
    const queryKey = ['articles', page, size]
    // queryFn里用page和size传参
    const queryFn = () => axios.get(`/api/articles?page=${page.value}&size=${size.value}`).then(res => res.data)
    // useQuery配置keepPreviousData,分页时保留上一页数据
    const { data, isLoading, isPreviousData } = useQuery(queryKey, queryFn, {
      keepPreviousData: true,
    })
    return { data, isLoading, isPreviousData, page }
  },
}
</script>

keepPreviousData的作用是:当queryKey变化(比如page从1变2),新请求还没回来时,data还是上一页的内容,不会空白;等新数据到了再替换,用户点分页时,界面不会“闪一下”,体验好很多。

增删改操作(mutation),vue-query咋做?

查询用useQuery,增删改这类“修改数据”的操作得用useMutation,它的逻辑是:触发mutation时执行mutationFn,成功后可以手动让相关查询的缓存失效(比如新增文章后,列表页重新请求最新数据)。

举个“新增文章”的例子:

<template>
  <div>
    <input v-model="title" placeholder="文章标题" />
    <button @click="createArticle" :disabled="isLoading">
      {{ isLoading ? '提交中...' : '发布文章' }}
    </button>
    <div v-if="error">{{ error.message }}</div>
  </div>
</template>
<script>
import { useMutation, useQueryClient } from '@tanstack/vue-query'
import axios from 'axios'
import { ref } from 'vue'
export default {
  name: 'CreateArticle',
  setup() {
    const title = ref('')
    const queryClient = useQueryClient() // 获取全局queryClient
    // mutationFn封装POST请求
    const mutationFn = (title) => axios.post('/api/articles', { title })
    // 调用useMutation,配置成功后回调
    const { mutate: createArticle, isLoading, error } = useMutation(mutationFn, {
      onSuccess: () => {
        // 新增成功后,让articles列表的缓存失效,自动重新请求
        queryClient.invalidateQueries(['articles'])
      },
    })
    return { title, createArticle, isLoading, error }
  },
}
</script>

这里invalidateQueries(['articles'])的作用是:找到所有queryKey包含articles的查询,标记它们为“过期”;下次组件访问这些查询时,会自动重新请求接口,这样列表页就能实时显示新增的文章,不用手动更新数据。

vue2用vue-query常见的坑,咋避?

  1. 版本装错:vue2必须用@tanstack/vue-query@3,装成v4会因依赖vue3 API报错,装包时要指定版本:npm i @tanstack/vue-query@3
  2. queryKey写得乱:如果多个请求用了一样的queryKey,会导致缓存冲突,文章列表”和“热门文章列表”,queryKey都用['articles']就会互相覆盖,解决方法:给不同逻辑的请求加唯一标识,比如['articles', 'hot']['articles', 'all']
  3. staleTime和cacheTime没搞懂:比如把staleTime设为0,数据一回来就标记为“过期”,下次访问会立刻重新请求,导致请求太频繁;cacheTime设太小,页面切回去时缓存已被清除,又得重新请求,得根据业务调:后台管理系统数据更新慢,staleTime可以设大(比如10分钟);资讯类App数据新鲜度高,staleTime设小(比如1分钟)。
  4. 和vuex的边界分不清:vue-query管“数据请求+缓存+状态”,vuex管“全局业务状态共享”(比如用户权限、主题配置),如果只是接口请求的状态,用vue-query更高效;如果是多组件共享的业务状态,还是得用vuex,别把两者的活搞混,不然代码会乱。

和axios、vue-resource比,vue-query优势在哪?

很多同学习惯直接用axios写请求,但对比下来,vue-query能省超多重复代码:

  • 自动状态管理:axios得自己写loading = true/false,vue-query直接给isLoadingisError这些状态。
  • 智能缓存:相同queryKey的请求自动缓存,页面刷新或组件复用都不重复请求;axios得自己存localStorage或vuex,还得处理缓存失效。
  • 后台同步:用户切到其他标签页再切回来,vue-query会自动检查数据是否“过期”,然后静默更新;axios要做这个,得监听visibilitychange事件、自己写逻辑。
  • 请求重试:接口失败时,vue-query能自动重试(还能配次数);axios得自己写重试拦截器。

简单说,vue-query把“数据请求环节的脏活累活”全做了,你只需要关心业务逻辑,对vue2项目来说,接入成本低、收益大——代码更简洁,维护更轻松,用户体验(比如分页不闪、后台自动更新)也更好。

看完这些,你应该对vue2里用vue-query有清晰思路了:从安装到发请求,从查询到修改,再到避坑和对比优势,核心就是让它帮你搞定数据层的繁琐事儿,要是你项目里还在手动管请求状态、缓存,不妨试试vue-query,体验下“写请求像呼吸一样简单”的感觉~要是实操中碰到新问题,评论区随时喊我,咱一起解决!

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门