TanStack生态与Server State思维

TanStack 的“Headless UI”理念

一句话:Headless UI = 只提供逻辑和状态,不规定长成什么样的组件,你用什么 UI 库、什么设计系统都行。

TanStack Query 文档 里,你会看到它一直强调:它是一个 data fetching & caching library,而不是一套组件库。这就是 headless 思路:

  • 它帮你做:请求、缓存、重试、失效、并发控制、状态机(loading / error / success)
  • 它完全不管:要不要用 Table,要不要用 Modal,用 Tailwind 还是 MUI 怎么画界面

机制上怎么做到“无头”的?

以 React 为例,useQuery 做的事只有两件:

  1. 建立一条 查询描述queryKey + queryFn(怎么拿数据)
  2. 暴露一堆 状态和操作dataerrorisLoadingrefetch

它不会替你 render 任何 DOM,也没有 <QueryTable/> 之类的 UI 组件。
你必须自己写组件,把这些状态“长”成你想要的界面。

tsximport { useQuery } from "@tanstack/react-query"; function UserList() { const { data, isLoading, error } = useQuery({ queryKey: ["users"], queryFn: () => fetch("/api/users").then((r) => r.json()), }); if (isLoading) return <div>加载中...</div>; if (error) return <div>出错了</div>; return ( <ul> {data.map((u: any) => ( <li key={u.id}>{u.name}</li> ))} </ul> ); }

同样一段逻辑:

  • 你可以换成 Chakra、MUI、Ant Design、Tailwind,完全不动 Query 配置
  • 你可以把 <ul> 换成 <Table>,甚至改成图表、卡片,也不用改 Query 的逻辑

为什么这让你自由选择 UI 库 / 设计系统?

因为逻辑层和视图层被硬拆开了:

层次谁来负责TanStack Query 负责吗?
API 调用、缓存、重试Query
什么时候重新拉数据Query 策略(失效、焦点、重连)
div/span/表格/卡片 长什么样你和 UI 库
Tailwind / CSS-in-JS / 设计系统你和团队设计规范

你可以同时满足:

  • 对数据:统一用 Query 做缓存、失效策略、乐观更新
  • 对 UI:任意换 skin,从裸 HTML 到重型设计系统,不动数据层

官方 Query 站点 本身也体现了这种生态:一堆库(Router、Table、Form、Virtual...),大多都是 headless 能力库,你自己决定如何渲染。

以后看到某个库说自己是 headless,可以直接问一句:
“它是给我状态/逻辑,还是帮我画好组件?”——只给状态/逻辑的,就是真·headless。

1 / 5