跳至主内容
版本:11.x

TanStack React Query

非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

Compared to our classic React Query Integration this client is simpler and more TanStack Query-native, providing factories for common TanStack React Query interfaces like QueryKeys, QueryOptions, and MutationOptions. We think it's the future and recommend using this over the classic client, read the announcement post for more information about this change.

技巧

您可以在 tRPC.io 首页体验此集成:https://trpc.io/?try=minimal-react#try-it-out

❓ Do I have to use an integration?

No! The integration is fully optional. You can use @tanstack/react-query using just a vanilla tRPC client, although then you'll have to manually manage query keys and do not get the same level of DX as when using the integration package.

utils/trpc.ts
ts
export const trpc = createTRPCClient<AppRouter>({
links: [httpBatchLink({ url: 'YOUR_API_URL' })],
});
utils/trpc.ts
ts
export const trpc = createTRPCClient<AppRouter>({
links: [httpBatchLink({ url: 'YOUR_API_URL' })],
});
components/PostList.tsx
tsx
function PostList() {
const { data } = useQuery({
queryKey: ['posts'],
queryFn: () => trpc.post.list.query(),
});
data; // Post[]
// ...
}
components/PostList.tsx
tsx
function PostList() {
const { data } = useQuery({
queryKey: ['posts'],
queryFn: () => trpc.post.list.query(),
});
data; // Post[]
// ...
}

设置

1. 安装依赖

需要安装以下依赖项:

npm install @trpc/server @trpc/client @trpc/tanstack-react-query @tanstack/react-query

2. 导入你的 AppRouter

非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

将你的 AppRouter 类型导入客户端应用中。该类型包含了整个 API 的结构定义。

utils/trpc.ts
ts
import type { AppRouter } from '../server/router';
utils/trpc.ts
ts
import type { AppRouter } from '../server/router';
技巧

使用 import type 可以确保类型引用在编译时被剥离,避免无意中将服务端代码导入客户端。更多信息请参阅 TypeScript 文档

3a. 设置 tRPC 上下文提供者

当依赖 React 上下文时(例如在 Next.js 等全栈框架中使用服务端渲染),必须为每个请求创建新的 QueryClient,避免用户共享相同缓存。您可以使用 createTRPCContextAppRouter 类型签名创建类型安全的上下文提供者和消费者。

utils/trpc.ts
tsx
import { createTRPCContext } from '@trpc/tanstack-react-query';
import type { AppRouter } from '../server/router';
 
export const { TRPCProvider, useTRPC, useTRPCClient } = createTRPCContext<AppRouter>();
utils/trpc.ts
tsx
import { createTRPCContext } from '@trpc/tanstack-react-query';
import type { AppRouter } from '../server/router';
 
export const { TRPCProvider, useTRPC, useTRPCClient } = createTRPCContext<AppRouter>();

随后创建 tRPC 客户端,并将应用包裹在 TRPCProvider 中(如下所示)。您还需设置并连接 React Query,其详细文档可供参考。

技巧

如果应用中已使用 React Query,您应当复用现有的 QueryClientQueryClientProvider。有关 QueryClient 初始化的更多信息,请参阅 React Query 文档

components/App.tsx
tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import { useState } from 'react';
import { TRPCProvider } from './utils/trpc';
function makeQueryClient() {
return new QueryClient({
defaultOptions: {
queries: {
// With SSR, we usually want to set some default staleTime
// above 0 to avoid refetching immediately on the client
staleTime: 60 * 1000,
},
},
});
}
let browserQueryClient: QueryClient | undefined = undefined;
function getQueryClient() {
if (typeof window === 'undefined') {
// Server: always make a new query client
return makeQueryClient();
} else {
// Browser: make a new query client if we don't already have one
// This is very important, so we don't re-make a new client if React
// suspends during the initial render. This may not be needed if we
// have a suspense boundary BELOW the creation of the query client
if (!browserQueryClient) browserQueryClient = makeQueryClient();
return browserQueryClient;
}
}
export function App() {
const queryClient = getQueryClient();
const [trpcClient] = useState(() =>
createTRPCClient<AppRouter>({
links: [
httpBatchLink({
url: 'http://localhost:2022',
}),
],
}),
);
return (
<QueryClientProvider client={queryClient}>
<TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>
{/* Your app here */}
</TRPCProvider>
</QueryClientProvider>
);
}
components/App.tsx
tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import { useState } from 'react';
import { TRPCProvider } from './utils/trpc';
function makeQueryClient() {
return new QueryClient({
defaultOptions: {
queries: {
// With SSR, we usually want to set some default staleTime
// above 0 to avoid refetching immediately on the client
staleTime: 60 * 1000,
},
},
});
}
let browserQueryClient: QueryClient | undefined = undefined;
function getQueryClient() {
if (typeof window === 'undefined') {
// Server: always make a new query client
return makeQueryClient();
} else {
// Browser: make a new query client if we don't already have one
// This is very important, so we don't re-make a new client if React
// suspends during the initial render. This may not be needed if we
// have a suspense boundary BELOW the creation of the query client
if (!browserQueryClient) browserQueryClient = makeQueryClient();
return browserQueryClient;
}
}
export function App() {
const queryClient = getQueryClient();
const [trpcClient] = useState(() =>
createTRPCClient<AppRouter>({
links: [
httpBatchLink({
url: 'http://localhost:2022',
}),
],
}),
);
return (
<QueryClientProvider client={queryClient}>
<TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>
{/* Your app here */}
</TRPCProvider>
</QueryClientProvider>
);
}

3b. 启用查询/变更键名前前缀的设置

若需为所有查询和变更添加特定键名前缀,请参阅查询键名前缀了解设置及用法示例。

3c. 脱离 React 上下文的设置

使用 Vite 等工具构建纯客户端渲染的 SPA 时,可在 React 上下文外部将 QueryClient 和 tRPC 客户端创建为单例对象。

utils/trpc.ts
ts
import { QueryClient } from '@tanstack/react-query';
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import { createTRPCOptionsProxy } from '@trpc/tanstack-react-query';
import type { AppRouter } from '../server/router';
export const queryClient = new QueryClient();
const trpcClient = createTRPCClient<AppRouter>({
links: [httpBatchLink({ url: 'http://localhost:2022' })],
});
export const trpc = createTRPCOptionsProxy<AppRouter>({
client: trpcClient,
queryClient,
});
utils/trpc.ts
ts
import { QueryClient } from '@tanstack/react-query';
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import { createTRPCOptionsProxy } from '@trpc/tanstack-react-query';
import type { AppRouter } from '../server/router';
export const queryClient = new QueryClient();
const trpcClient = createTRPCClient<AppRouter>({
links: [httpBatchLink({ url: 'http://localhost:2022' })],
});
export const trpc = createTRPCOptionsProxy<AppRouter>({
client: trpcClient,
queryClient,
});
components/App.tsx
tsx
import { QueryClientProvider } from '@tanstack/react-query';
import React from 'react';
import { queryClient } from './utils/trpc';
export function App() {
return (
<QueryClientProvider client={queryClient}>
{/* Your app here */}
</QueryClientProvider>
);
}
components/App.tsx
tsx
import { QueryClientProvider } from '@tanstack/react-query';
import React from 'react';
import { queryClient } from './utils/trpc';
export function App() {
return (
<QueryClientProvider client={queryClient}>
{/* Your app here */}
</QueryClientProvider>
);
}

4. 获取数据

现在你可以使用 tRPC 的 React Query 集成来调用 API 上的查询和变更操作。

components/user-list.tsx
tsx
import { useMutation, useQuery } from '@tanstack/react-query';
import { useTRPC } from '../utils/trpc';
export default function UserList() {
const trpc = useTRPC(); // use `import { trpc } from './utils/trpc'` if you're using the singleton pattern
const userQuery = useQuery(trpc.getUser.queryOptions({ id: 'id_bilbo' }));
const userCreator = useMutation(trpc.createUser.mutationOptions());
return (
<div>
<p>{userQuery.data?.name}</p>
<button onClick={() => userCreator.mutate({ name: 'Frodo' })}>
Create Frodo
</button>
</div>
);
}
components/user-list.tsx
tsx
import { useMutation, useQuery } from '@tanstack/react-query';
import { useTRPC } from '../utils/trpc';
export default function UserList() {
const trpc = useTRPC(); // use `import { trpc } from './utils/trpc'` if you're using the singleton pattern
const userQuery = useQuery(trpc.getUser.queryOptions({ id: 'id_bilbo' }));
const userCreator = useMutation(trpc.createUser.mutationOptions());
return (
<div>
<p>{userQuery.data?.name}</p>
<button onClick={() => userCreator.mutate({ name: 'Frodo' })}>
Create Frodo
</button>
</div>
);
}