使用 TanStack Query 管理服务器状态(Server State)

为什么需要
TanStack Query 工作在客户端,用来在客户端管理服务器状态。
服务器状态有其独特的特点:
-
它存储在远程,我们无法直接控制。
-
它需要异步获取。
-
它可能被其他人修改,导致我们本地的数据“过时”(stale)。
-
它和缓存、重试、数据同步等概念紧密相关。
想象下面这些场景:
-
代码冗余:每个需要请求数据的组件,几乎都要重复写一遍 isLoading, error, data 这三个状态以及 useEffect 中的逻辑。
-
缺少缓存:如果用户切换到其他页面再切回来,这个组件会重新挂载,useEffect 会再次执行,数据会重新请求。这不仅浪费了用户的流量,也增加了服务器的压力,并且用户会再次看到 Loading… 的状态,体验不佳。
-
数据状态不同步:假设你在一个“帖子列表”页面,又在另一个“用户详情”页面的侧边栏显示了同一个用户的帖子。如果用户在详情页删除了一个帖子,列表页的数据是不会自动更新的,因为它们是两个独立的请求和状态。
-
复杂的状态管理:当涉及到分页、无限滚动、轮询等高级场景时,useEffect 里的逻辑会变得异常复杂和难以维护。
-
后台自动更新困难:当用户长时间停留在页面上时,屏幕上的数据可能已经“过时”了。我们如何能在不打扰用户的情况下,在后台悄悄更新数据呢?用 useEffect + setInterval?这会引入新的复杂性。
TanStack Query 使用 query key 唯一标识我们的 state ,给其提供缓存,使得分散在各处的 fetch 请求可以使用同一份东西,让整个系统联系起来。
另可见:Server Action,TanStack Query … 我到底要用谁
快速上手
安装
1 | pnpm add @tanstack/react-query |
定义 Provider
新建一个 src\providers\QueryProvider.tsx:
这里我额外引入了 ReactQueryDevtools,这样做之后浏览器能显示出专属的 dev tool。
1 | "use client"; |
然后再 main.tsx 或者 src\app\layout.tsx 里使用它:
1 | export default function RootLayout({ |
使用示例
组件里使用示例:
核心就是其中的 useQuery hook,这个东西能解构出来一堆有用的玩意,其中的 data 就是我们要的数据。
1 | import { useQuery } from '@tanstack/react-query'; |
代码组织
社区推荐的方式是把 query options 拆分管理,便于复用,所以我们新建一个像是这样的文件:
src\features\todos\createTodoQueryOptions.ts
1 | import { queryOptions } from "@tanstack/react-query"; |
注意我们这里并不是定义了一个死的对象,而是用了 queryOptions 函数。
之后使用的时候,就可以直接引入了:
src\features\todos\components\todo-manager.tsx
1 | import createTodoQueryOptions from "../createTodoQueryOptions"; |
使用 useMutation 变更数据
我们使用一个 useMutation hook:
1 | const { mutate } = useMutation({ |
该 hook 内部先需要我们定义一个 mutationFn,其实就是我们用来做数据变更的函数。结合 [[server action & useActionState hook | server action]] 使用的话,这里就可以填入一个 server action 函数。
解构出来的 mutate ,其实就是我们下面需要用的东西。
在组件中使用:
1 | mutate(content); |
相当于使用了我们定义的 mutationFn。
那么,我们为什么不直接使用 fetch 等函数?
我们注意到,除了 mutationFn ,我们还可以定义一系列回调函数。
这使得我们可以在突变生命周期的任何阶段快速轻松地执行副作用。这些选项在以下场景中会很有用:
- 突变后使缓存失效
- 重新获取查询
- 乐观更新
不过,如果你不需要在 mutation 进行的生命周期中做什么事,那也确实不需要用 useMutation 了。
我们大可以直接用一遍封装好的 fetch 函数,然后手动执行一次缓存失效:
1 | queryClient.invalidateQueries({ queryKey: ['todos'] }) |
- 标题: 使用 TanStack Query 管理服务器状态(Server State)
- 作者: 三葉Leaves
- 创建于 : 2025-09-08 00:00:00
- 更新于 : 2025-09-26 18:04:55
- 链接: https://blog.oksanye.com/63dc31fb68e4/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。