作为一个深耕Vue 3 + Vite
的开发者,我为什么把“全家桶”
全扔了?
曾经的我:
pinia
管全局状态vue-router
管路由element-plus
的<el-table>
管表格- 自己封装
useAxios
管接口缓存
每新增一个需求,就要再学一套 API,再踩一堆坑。
直到某天,隔壁React
同事甩给我一张截图: TanStack Query DevTools
里,缓存
、轮询
、失效
一屏看全;
我酸了——这不就是Vue
梦寐以求的“数据层圣杯”
吗?
更离谱的是,他轻描淡写一句: “这玩意儿 Vue 也能用,官方包@tanstack/vue-query
都出到 v5 了。”
于是,我试了一下午,结果: 我把Pinia
、el-table
、手写缓存
全部卸载了;
路由仍保留官方 vue-router@4
,因为 TanStack Router 目前仅支持 React。
一个 TanStack(Query + Table + Form + Virtual),真·一个库组合,搞定 90 % 的痛点。
什么是 TanStack
TanStack 是一组「无头(Headless
)+ 类型安全
+ 跨框架
」的微型库集合。
当前 Vue 生态可直接使用的成员:
场景 | 库名 | 一句话定位 |
---|---|---|
数据/服务端状态 | @tanstack/vue-query |
请求、缓存、轮询、乐观更新一把梭 |
表格/数据网格 | @tanstack/vue-table |
万行数据 60 FPS,UI 100 % 自定义 |
表单 | @tanstack/vue-form |
类型安全的无头表单 |
虚拟滚动 | @tanstack/vue-virtual |
长列表一次性渲染不卡 |
注意:TanStack Router 尚未推出 Vue 版本,路由请继续使用官方
vue-router@4
。
TanStack 优势
- 类型安全到牙齿: 纯
TypeScript
编写,自动补全 + 编译时校验。 - 真正的无头(Headless): 只给逻辑,不给
UI
;样式、组件库随意换。 - 跨框架同构:
Query
/Table
/Form
/Virtual
均已支持Vue
、React
、Solid
、Svelte
、Angular
,学会一次,到处复用。
- TanStack Query DevTools: 一键调试缓存;统一
ESLint
/Vite
插件。
如何快速上手 TanStack(Vue 3)
1. 安装核心包
npm i @tanstack/vue-query @tanstack/vue-table
2. 启用插件
// main.ts
import { createApp } from "vue";
import { VueQueryPlugin } from "@tanstack/vue-query";
import App from "./App.vue";
createApp(App).use(VueQueryPlugin).mount("#app");
3. 30 秒跑通「用户列表 + 搜索 + 分页」
<script setup lang="ts">
import { useQuery } from "@tanstack/vue-query";
import {
useVueTable,
flexRender,
getCoreRowModel,
} from "@tanstack/vue-table";
const fetchUsers = async () => (await fetch("/api/users")).json();
const { data } = useQuery({ queryKey: ["users"], queryFn: fetchUsers });
const columns = [
{ accessorKey: "id", header: "ID" },
{ accessorKey: "name", header: "姓名" },
{ accessorKey: "email", header: "邮箱" },
];
const table = useVueTable({
get data() {
return data.value ?? [];
},
columns,
getCoreRowModel: getCoreRowModel(),
});
</script>
<template>
<table class="w-full">
<thead>
<tr v-for="hg in table.getHeaderGroups()" :key="hg.id">
<th v-for="h in hg.headers" :key="h.id">
{{ flexRender(h.column.columnDef.header, h.getContext()) }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="row in table.getRowModel().rows" :key="row.id">
<td v-for="cell in row.getVisibleCells()" :key="cell.id">
{{ flexRender(cell.column.columnDef.cell, cell.getContext()) }}
</td>
</tr>
</tbody>
</table>
</template>
但 TanStack 的野心远不止 Vue
框架 | 已支持包 | 使用体验 |
---|---|---|
React | @tanstack/react-* |
hooks |
Vue | @tanstack/vue-* |
Composition API |
Solid | @tanstack/solid-* |
signals |
Svelte | @tanstack/svelte-* |
stores |
Angular | @tanstack/angular-* |
inject |
路由除外:目前仅 React 有
@tanstack/react-router
,Vue 仍需vue-router@4
。
迁移前后对比(真实 Vue 3 项目)
维度 | 迁移前 | 迁移后 |
---|---|---|
状态管理 & 数据层 | Pinia + 手写缓存 | @tanstack/vue-query |
路由 | vue-router@4 |
保持不变 (无 Vue 版 TanStack Router) |
表格 | element-plus <el-table> |
@tanstack/vue-table |
包体积(gzip) | 312 KB | 198 KB |
大表格 FPS | 45–55 | 60(虚拟滚动) |
代码行数 | 2,300 | 1,100 |
最后
TanStack 把「数据、表格、表单、虚拟滚动」
这些最通用、最痛点的需求抽象成无头、跨框架、类型安全的微型库;
如果你也想丢掉Pinia
、el-table
、手写缓存
,却又不想被全家桶绑架,现在就把npm i @tanstack/vue-query @tanstack/vue-table
敲进终端,一个库组合,搞定 90 % 的现代 Web 需求。
- TanStack 官网:
https://tanstack.com/