oRPC + TanStack Query 的协同工作模式
https://orpc.unnoq.com/docs/integrations/tanstack-query
第一部分:oRPC 客户端的基础使用(不依赖任何请求库)
在不使用任何状态管理库的情况下,oRPC 客户端本身就是一个功能强大且类型安全的请求工具。
步骤 1:创建客户端实例
首先,您需要创建一个客户端实例。这个实例是您前端应用与后端 API 通信的唯一入口。您需要一个 “Link” 来告诉客户端如何与后端通信。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import { createORPCClient } from '@orpc/client'; import { RPCLink } from '@orpc/client/fetch';
import type { AppRouter } from '../../api-gateway/src/router'; import type { RouterClient } from '@orpc/server';
const link = new RPCLink({ url: 'http://localhost:3000/rpc', headers: () => { const token = localStorage.getItem('token'); if (token) { return { Authorization: `Bearer ${token}`, }; } return {}; }, });
export const client: RouterClient<typeof AppRouter> = createORPCClient(link);
|
步骤 2:发起请求
创建客户端后,您就可以在代码的任何地方(例如 React/Vue 组件、或普通的业务逻辑文件中)发起请求了。整个过程就像调用一个本地的异步函数,并且拥有完美的自动补全和类型检查。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import { client } from '../lib/orpcClient';
async function fetchPlanets() { try { const planets = await client.planet.list({ limit: 10 });
console.log(planets[0].name);
} catch (error) { console.error("请求失败:", error); } }
|
步骤 3:错误处理 (safe
工具)
为了避免到处写 try/catch
,oRPC 提供了一个非常有用的 safe
工具函数,它可以将 Promise 的结果包装成一个元组 [error, data]
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import { client } from '../lib/orpcClient'; import { safe, isDefinedError } from '@orpc/client';
async function createPlanet(name: string) { const [error, newPlanet] = await safe(client.planet.create({ name }));
if (error) { if (isDefinedError(error)) { alert(`创建失败: ${error.message}, 原因: ${error.data.reason}`); } else { alert(`发生未知错误: ${error.message}`); } return; }
console.log('新行星已创建:', newPlanet.id); }
|
第二部分:配合 TanStack Query - 现代前端数据请求的最佳实践
虽然 oRPC 的基础客户端很好用,但在现代前端应用中,我们需要的不仅仅是数据请求。我们还需要服务器状态管理,包括:
- 缓存:避免重复请求相同的数据。
- 自动重新验证:在用户切换窗口或网络重连时自动更新数据。
- 加载与错误状态管理:轻松获取 UI 所需的
isLoading
, isError
等状态。
- 修改与缓存失效:在创建或更新数据后,能方便地让相关的查询缓存失效并重新获取。
这正是 TanStack Query 所做的。oRPC 与它进行了深度集成,让这一切变得极其简单。
步骤 1:安装集成包
1
| pnpm add @orpc/tanstack-query @tanstack/react-query
|
步骤 2:创建 oRPC Query 工具集 (Utils
)
这是连接 oRPC 和 TanStack Query 的桥梁。您需要用 oRPC 提供的工具函数来包装您之前创建的 client
实例。
1 2 3 4 5 6 7
| import { createTanstackQueryUtils } from '@orpc/tanstack-query'; import { client } from './orpcClient';
export const orpc = createTanstackQueryUtils(client);
|
步骤 3:核心用法(以 React 为例)
现在,您可以像使用原生的 TanStack Query 一样,但是 oRPC 集成包会为您自动处理掉最繁琐的部分(queryKey
和 queryFn
)。
A. 查询数据 (useQuery
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import { useQuery } from '@tanstack/react-query'; import { orpc } from '../lib/orpcQuery';
function PlanetList() { const { data, isLoading, isError } = useQuery( orpc.planet.list.queryOptions({ input: { limit: 10 } }) );
if (isLoading) return <div>正在加载...</div>; if (isError) return <div>加载失败!</div>;
return ( <ul> {data.map(planet => <li key={planet.id}>{planet.name}</li>)} </ul> ); }
|
B. 修改数据 (useMutation
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import { useMutation, useQueryClient } from '@tanstack/react-query'; import { orpc } from '../lib/orpcQuery';
function CreatePlanetForm() { const queryClient = useQueryClient();
const mutation = useMutation( orpc.planet.create.mutationOptions({ onSuccess: () => { queryClient.invalidateQueries({ queryKey: orpc.planet.list.key(), }); }, }) );
const handleSubmit = (event) => { event.preventDefault(); const name = new FormData(event.target).get('name') as string; mutation.mutate({ name }); };
return ( <form onSubmit={handleSubmit}> <input name="name" disabled={mutation.isPending} /> <button type="submit" disabled={mutation.isPending}> {mutation.isPending ? '创建中...' : '创建行星'} </button> </form> ); }
|
C. 无限滚动 (useInfiniteQuery
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import { useInfiniteQuery } from '@tanstack/react-query'; import { orpc } from '../lib/orpcQuery';
function InfinitePlanetList() { const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery( orpc.planet.listWithCursor.infiniteOptions({ input: (pageParam) => ({ cursor: pageParam }), initialPageParam: 0, getNextPageParam: (lastPage) => lastPage.nextCursor, }) );
}
|
总结:oRPC + TanStack Query 的协同工作模式
您可以这样理解它们的关系:
- oRPC Client (
client
):是类型安全的管道工。它负责建立从前端到后端的、数据类型完全正确的通信管道。
- TanStack Query:是智能的水库和调度中心。它决定了什么时候通过管道取水(发起请求)、取来的水(数据)要缓存多久、什么时候水变质了需要重新取(缓存失效和重新验证)。
@orpc/tanstack-query
(orpc
a.k.a. Utils):是管道工和调度中心的“智能适配器”。它将 oRPC 的类型安全能力无缝对接给 TanStack Query,自动完成了所有繁琐的配置工作,让您可以专注于业务逻辑,同时享受两个库带来的最大优势。