木灵鱼儿 - vue-query
type: channel
link: https://www.mulingyuer.com/tag/vue-query/
items: 03-Vue Query 高级进阶：应对复杂业务场景的硬核套路
items: 02-Vue Query 快速入门：从零构建你的第一个声明式查询
items: 01-异步状态管理新范式：为什么在 Vue 3 中使用 vue-query？

03-Vue Query 高级进阶：应对复杂业务场景的硬核套路
type: item
date: 2026-06-23T16:21:01+08:00
description: 前言在前两篇文章中，我们完成了 Vue Query 的思维转变并掌握了基础实战。然而，在真实的中大型项目中，我们往往会遇到许多刁钻、复杂的业务需求。今天，我们将分享 4 个应对复杂场景的高级套路，帮助你彻底玩转 Vue Query。[hide]优雅的 Key 层次设计与全局缓存失效业务场景在需要登录鉴权的项目中，当用户点击“退出登录”时，我们必须立即清空所有与该用户相关的敏感接口缓存。否则，当下一个用户登录时，可能会短暂看到上一个用户的数据，造成严重的数据串线和安全隐患。如果一个一个去手动清理 user-detail、notice-list、billing-history，不仅代码极其繁琐，而且后续新增接口时极易遗漏。解决方案：多级 Key 继承与前缀匹配Vue Query 的缓存失效机制（invalidateQueries）是基于前缀匹配的。我们可以利用这一特性，设计一套优雅的 Key 层次结构。首先，定义一个基础键：/** 必须登录的查询基础 key */ export const REQUIRED_QUERY_KEY = ["required"];然后，让所有需要登录鉴权的接口 Key 都继承这个基础键：用户信息 Key：[...REQUIRED_QUERY_KEY, "user-detail"]公告列表 Key：[...REQUIRED_QUERY_KEY, "notice-list"]API 地址 Key：[...REQUIRED_QUERY_KEY, "api-address"]当用户登出时，我们只需要一行代码：import { queryClient } from "@/plugins/tanstack/vue-query"; import { REQUIRED_QUERY_KEY } from "./query-keys"; /** 将所有需要登录的查询标记为过期并清空 */ export function invalidateRequiredQueries() { return queryClient.invalidateQueries({ queryKey: REQUIRED_QUERY_KEY }); }原理解析：由于 Vue Query 会匹配所有以 ["required"] 开头的 Key，因此调用 invalidateRequiredQueries 会自动、一次性地让所有敏感接口的缓存全部失效并重新拉取。这极大地提升了系统的安全性和可维护性。分页与过滤：如何消除页面切换的闪烁感？业务场景在公告列表、账单日志等分页表格中，当用户点击“下一页”时，由于新一页的数据正在网络传输中，页面通常会瞬间变为空白，或者显示一个全屏的 Loading 遮罩。等数据加载完后，表格再重新渲染。这种频繁的“空白 -> 渲染”切换会产生强烈的闪烁感，用户体验非常粗糙。解决方案：placeholderData: keepPreviousDataVue Query 提供了 keepPreviousData 配置项，专门用来解决分页切换的闪烁问题。import { computed, toValue, type Ref } from "vue"; import { keepPreviousData, useQuery } from "@tanstack/vue-query"; import { getNoticeList, type GetNoticeListParams } from "@/api/notice"; export const NOTICE_LIST_KEY = ["notice-list"]; export function useGetNoticeList(params: Ref<GetNoticeListParams>) { return useQuery({ queryKey: computed(() => [...NOTICE_LIST_KEY, toValue(params)]), queryFn: () => getNoticeList(toValue(params)), // 核心配置：在请求新数据时，保持显示上一页的数据 placeholderData: keepPreviousData }); }原理解析：当用户切换到第 2 页时，Vue Query 会在后台发起第 2 页的请求。在第 2 页数据返回之前，页面上依然显示第 1 页的数据，表格不会变空，避免了布局闪烁。你可以配合 isFetching 状态，在表格上方显示一个轻量级的加载条（如进度条），提示用户正在加载。一旦第 2 页数据返回，Vue Query 会瞬间将表格内容替换为第 2 页数据，实现无缝平滑过渡。突破 Setup 限制：在非…

02-Vue Query 快速入门：从零构建你的第一个声明式查询
type: item
date: 2026-06-23T16:19:56+08:00
description: 前言在上一篇文章中，我们探讨了为什么要引入 @tanstack/vue-query 以及它与 Axios 的协同关系。今天，我们将正式进入实战阶段，手把手教你如何在 Vue 3 项目中搭建 Vue Query 的骨架，掌握其最核心的 API 与配置，并深入探讨如何利用调试工具和轻量级缓存更新策略提升开发效率。[hide]基础配置：搭建 Vue Query 的骨架在 Vue 3 项目中集成 Vue Query 非常简单，主要分为两步：初始化 QueryClient 和注册插件。第一步：初始化 QueryClient我们在项目根目录的 src/plugins/tanstack/vue-query.ts 中创建并配置 QueryClient 实例。import { QueryClient, VueQueryPlugin } from "@tanstack/vue-query"; import type { App } from "vue"; // 实例化 QueryClient，并导出为全局单例 export const queryClient = new QueryClient({ defaultOptions: { queries: { // 1. 因为我们的 Axios 拦截器已经实现了请求重试，所以这里关闭 Vue Query 的自动重试 retry: false, // 2. 默认关闭窗口聚焦时自动刷新（按需在单个接口开启，省流量） refetchOnWindowFocus: false } } });架构小贴士：为什么要把 queryClient 导出为全局单例？因为在实际项目中，我们经常需要在非 Setup 上下文（如路由守卫、Pinia Store、Axios 拦截器或普通 JS/TS 工具函数）中操作缓存。通过导出单例，我们可以在任何地方直接 import { queryClient } 并调用其 API（如 queryClient.setQueryData）。第二步：注册 VueQueryPlugin 与调试工具配置在同一个文件中，我们定义一个注册函数。对于接口数据管理工具而言，可视化调试能力至关重要。如果没有方便的可视化操作，调试缓存状态、查看数据是否过期会变得极其麻烦。根据 Vue Query 官方 Devtools 文档，官方目前提供了三种主流的调试方式：官方 Devtools 控制组件：通过在项目中引入 @tanstack/vue-query-devtools 组件，在页面右下角渲染一个悬浮的调试面板。集成到 vite-plugin-vue-devtools：Vue Query 可以无缝集成到 Vue 官方的 Vite 插件中，在 Vite 开发者面板中直接查看 Query 状态。浏览器插件（Chrome/Firefox Extension）：安装官方提供的浏览器独立扩展程序。在实际开发中，由于控制组件会侵入项目代码，而 Vite 插件面板有时不够直观，使用浏览器独立插件是许多开发者最习惯、最清爽的选择。为了让浏览器插件能够识别到我们项目中的 queryClient 实例，我们需要在开发环境下将其挂载到全局：export const registerVueQuery = (app: App) => { // 配合浏览器插件 Devtools 使用，且只在开发环境暴露 if (import.meta.env.DEV) { window.__TANSTACK_QUERY_CLIENT__ = queryClient; } app.use(VueQueryPlugin, { queryClient }); };挂载后，打开 Chrome 的 Vue Query Devtools 插件，即可完美识别并可视化操作我们应用中的所有缓存数据。最后，在 main.ts 中引入并调用 registerVueQuery(app) 即可完成初始化。核心 API：useQuery 的基本用法useQuery 是 Vue Query 中最常用的 API，用于执行“读”操作（获取数据）。我们以一个标准的用户信息接口为例来讲解。import { useQuery } from "@tanstack/vue-query"; import { getUserDetail } from "@/api/user"; export const USER_DETAIL_KEY = ["user-detail"]; export function useUserDetail() { return useQuery({ // 1. QueryKey：缓存的唯一标识，必须是数组 queryKey: USER_DETAIL_KEY, // 2. Quer…

01-异步状态管理新范式：为什么在 Vue 3 中使用 vue-query？
type: item
date: 2026-06-23T16:08:00+08:00
description: 前言在现代 Web 应用开发中，API 数据请求与状态同步是前端架构的核心环节。在 Vue 3 项目中，开发者通常习惯于使用 Axios 结合组件生命周期钩子（如 onMounted）来获取数据，并手动维护 loading、error 等响应式状态。然而，随着应用复杂度的提升，这种命令式的数据管理模式在性能、代码复用性以及用户体验上面临诸多挑战。本文将从架构设计的角度，探讨如何通过引入 @tanstack/vue-query 实现从“命令式数据获取”向“声明式异步状态管理”的范式转变，并阐述其与 Axios 的协同工作机制。传统前端请求的痛点在没有引入专门的异步状态管理工具前，一个典型的 Vue 3 数据请求组件通常采用如下模式： 加载中... 出错了：{{ error.message }} 用户：{{ data.name }} 这种命令式写法在简单场景下直观易懂，但在中大型项目中会暴露以下架构缺陷：状态冗余与样板代码：每个需要请求数据的组件都必须重复定义 loading、error、data 这一套响应式变量，并编写相似的 try-catch-finally 逻辑，导致代码冗余。重复请求与带宽浪费：若页面中多个独立挂载的子组件依赖同一份数据（例如当前登录用户信息），它们各自挂载时会触发多次相同的 API 请求，缺乏统一的请求合并机制。缓存缺失与页面闪烁：用户在不同路由间切换时，组件的销毁与重新挂载会频繁触发网络请求，导致页面出现“空白 -> 加载中 -> 渲染”的闪烁，无法提供即时响应的体验。数据过期与同步困难：客户端难以感知服务器端数据的实时变化。当用户在 A 页面修改了数据，B 页面缓存的数据无法自动或优雅地同步更新。核心概念：Axios 与 Vue Query 的本质区别要解决上述痛点，首先需要理清网络传输与状态管理在前端架构中的职责边界。Axios 的定位：传输层（Transport Layer）它是一个优秀的 HTTP 客户端，专注于“如何安全、正确地执行网络通信”。其职责包括：请求/响应拦截、Token 刷新、超时处理、请求重试、数据序列化等网络细节。它不关心数据在客户端的生命周期、共享范围以及缓存策略。Vue Query 的定位：异步状态管理层（Asynchronous State Management）它是一个强大的状态管理器，专注于“如何管理、同步和缓存客户端的服务器状态”。其职责包括：数据缓存生命周期管理、请求去重、后台静默刷新、条件触发、垃圾回收等。它不关心底层的网络请求是通过 Axios、Fetch 还是 WebSocket 实现的。协同工作模式在优秀的架构设计中，两者并非竞争关系，而是互补的。Axios 负责发送请求，Vue Query 负责管理请求结果。graph LR Component[Vue 组件] -->|useQuery| VueQuery[Vue Query 缓存层] VueQuery -->|未命中缓存/已过期| Axios[Axios 传输层] Axios -->|发起 HTTP 请求| Server[后端服务器] Server -->|返回数据| Axios Axios -->|交付数据| VueQuery VueQuery -->|响应式更新| Component引入 Vue Query 带来的核心收益声明式数据获取开发者不再需要手动维护 loading、error 状态。Vue Query 的 useQuery 会自动解构出这些状态，使组件逻辑更加聚焦于 UI 渲染：const { data, isLoading, isError, error } = useQuery({ queryKey: ["user-detail"], queryFn: getUserDetail });自动请求去重（Deduplication）当多个组件在同一时刻调用相同的 useQuery（拥有相同的 queryKey）时，Vue Query 会将它们合并。底层的网络请求只会发送一次，所有组件共享同一个响应结果。开箱即用的缓存与后台静默刷新（SWR 机制）Vue Query 采用了经典的 SWR (Stale-While-Revalidate) 缓存失效策略：当组件挂载时，如果缓存中已有数据，Vue Query 会立即返回缓存数据，让用户瞬间看到内容。与此同时，它会在后台静默发起请求，获取最新数据。当最新数据返回后，它会静默更新缓存并响应式地渲染页面，确保数据最终一致性。极简的全局状态共享无需通过 Pinia 编写繁琐的 action 和 state，直接通过相同的 QueryKey 即可在任意组件间共享数据，降低了状态管理的复杂度。项目实战：它们是如何在项目中优雅配合的？在实际项目中，我们通过将…