hello!大家好!今天,我给大家分享一个我超级喜欢的技术栈的故事:TanStack!
前端工具的竞争,表面上是 API 的竞争,底层其实是对复杂度的重新分配:哪些事情交给框架,哪些事情交给应用,哪些事情应该由类型系统提前约束。
一个库能不能长期留下来,往往不只取决于它能不能解决一个问题,也取决于它能不能在下一个问题出现时继续保持同一套判断。
今天,让我们一起来了解一下 TanStack 的技术“史诗”!
它最初因为 React Query 被更多开发者认识,后来逐步扩展到路由、全栈框架、表格、表单、虚拟列表、AI 与开发工具。今天的 TanStack 已经不太像一组彼此独立的工具,而更像一套围绕 TypeScript、数据流和应用边界组织起来的前端应用栈。
让我们沿着产品技术栈一步步向前走:React Query 解决了什么,TanStack 为什么要改名,竞品各自把复杂度放在哪里,以及这些公开 Issue 如何暴露出它的优势与代价。
在 React Query 出现之前,前端获取数据通常会混合几种工作:组件启动请求、显示 loading、处理错误、保存结果、判断结果是否过期、响应窗口重新聚焦、处理重复请求,以及在修改数据后让相关页面重新获取数据。
这些工作并不难单独完成,难的是它们会在每个页面重复出现。一个页面写一套 useEffect,另一个页面写一套全局状态,最后大家都要回答同样的问题:这份数据现在属于谁?多久算旧?两个组件同时请求同一个资源时,能不能复用结果?修改完成后,哪些缓存需要失效?
这些问题贯穿着 React 项目的方方面面,无论开发者水平是高是低,都需要直接面对这个问题。在一个团队里,给出一份稳定、高效且让大家都满意的方案并不简单。
React Query 的重要变化,是把问题从“如何在组件里发请求”改成“如何声明一份服务器状态”。在今天的 TanStack Query 里,查询键、查询函数和缓存生命周期组成了一个相对完整的模型。
最小的使用方式看起来很简单:
const todosQuery = useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
})
少写几行请求代码价值并不大,这几个概念被固定了下来才是重头戏:
queryKey 是缓存的身份,也是依赖关系的声明;
查询结果可以在组件之间共享,并自动去重;
新数据可以在后台刷新,页面不必每次都回到空白 loading;
mutation 可以和失效、乐观更新、回滚联系起来;
缓存、重试、离线和开发调试都有统一入口。
以上功能涉及到了 Web 开发的方方面面,每一个都可以单独拉出来开发一个 npm 包,但是 Tanstack Query 直接给我们提供了一个完整的、强类型的无敌解决方案!
这让“服务器状态”和“客户端状态”开始分开。输入框是否展开、弹窗是否打开,仍然适合交给组件状态或状态管理库;来自接口、会过期、可能被别的用户修改的数据,则应该有自己的缓存和同步机制。

React Query 最早的影响,正是让很多团队意识到:不是所有状态都应该塞进 Redux,也不是所有异步逻辑都应该散落在副作用里。
2022 年发布的 v4 是一次关键转折。官方在 v4 发布文章 中说明,项目从过去的 React 专属库,重构为无框架核心加框架适配器的形式,并开始支持 Vue、Svelte 和 Solid。
这次改名不是简单换一个 npm 包名。它改变了项目的边界:核心缓存、查询客户端、订阅和状态转换尽量不依赖具体 UI 框架;React 的 hook、Vue 的组合式接口,属于上层适配器。这样做有两个直接收益。
第一,维护者可以复用同一套数据逻辑。第二,用户学到的不是某个框架的技巧,而是一套可以迁移的服务器状态模型。v4 还加入了更完整的离线支持、持久化和 React 18 兼容能力,说明它已经不满足于“帮你发请求”,而是在争取成为异步状态的基础设施。
到了 v5,项目继续收紧 API,拥抱更现代的 TypeScript 和 React 并发模型。这种演进方式也埋下了 TanStack 的一个特征:它愿意为了长期模型调整短期兼容性,但会把迁移说明、类型边界和取舍放到台面上讨论,团队开发人员在 github 上发布了大量解释性回复,同时也写了很多实用的教程和博客。


上图是 TanStack 当前产品矩阵的一个概览。它的扩张不是简单地“看到什么热门就做什么”,大致可以按五层来理解。
TanStack Router 是这套体系的路由基础。它把路由树、路径参数、搜索参数、loader、预加载和 pending 状态纳入类型系统。尤其是搜索参数,它不再只是一个字符串,而可以有明确的结构、解析和序列化规则。
这种设计很适合数据密集型应用:列表筛选、分页、排序和详情页状态都能映射到 URL,loader 又可以和查询缓存配合。路由因此不只是页面切换工具,而变成了应用数据流的一部分。

这种设计真的非常 nice,我们不用再去花时间精力找各种不同的解决方案。
TanStack Start 则在 Router 之上继续向全栈靠近。它提供服务端渲染、流式输出、服务端函数、服务端路由和面向不同运行时的构建结果。官方目前仍标记为 RC,这个状态很重要:它代表产品方向已经清楚,但基础设施仍处于快速打磨阶段。
Query 是最成熟、最容易理解的一层:它负责远程数据的缓存、同步和更新。
DB 试图把客户端数据存储做得更具反应性,让接口数据可以在本地形成可查询、可订阅的关系。Store 更靠近一般客户端状态,但仍然延续轻量、类型友好的思路。AI 则把流式文本、工具调用、多模态和 agent 场景纳入同一套 TypeScript 接口。
官网当前将 DB 标为 beta、AI 标为 beta、Store 标为 alpha。把这些状态公开标出,既是风险提示,也是一种产品管理方式:用户可以清楚知道 Query、Router 这样的成熟工具,与新工具之间并不处在同一个稳定等级。
TanStack Table 的定位很典型:它是 headless 的表格引擎,不替你决定 HTML、CSS 和组件外观。排序、筛选、分组、分页、行选择等能力由它提供,最终如何渲染由应用自己决定。
这条路线和“开箱即用”的表格组件不同。它牺牲了一部分上手速度,换来设计自由、组件库兼容性和更细的性能控制。Form 与 Hotkeys 也延续同样思路:提供状态和行为模型,不强迫应用接受一套视觉语言。
Virtual 负责大列表、大表格的窗口化渲染,让应用只渲染视口附近的数据。它和 Table 的组合很自然:Table 管理数据模型,Virtual 管理可见范围。
Pacer 更像是性能调度工具,用来处理节流、防抖、批处理和高频更新。它们共同说明 TanStack 的关注点正在从“有没有功能”转向“功能在复杂数据量和高频交互下是否还能保持可控”。

Devtools 负责观察查询、路由和缓存;Config、CLI 和 Intent 则在把工程配置、项目初始化与 AI agent 的工作方式纳入产品范围。尤其是 Intent 这类工具,反映出维护者开始考虑一个新问题:未来不只有人会阅读文档和修改代码,agent 也需要可靠地发现、安装和使用这些能力。
从 React Query 到产品矩阵,TanStack 的第一步是把服务器状态、路由、全栈边界和数据视图逐渐放进一套可组合的技术栈。下篇将继续从竞品和公开 Issue 出发,看看这些选择在真实工程里意味着什么。
