Skip to main content
Version: 10.x

服务器端助手

服务器端辅助程序为你提供了一组辅助程序函数,你可以使用它们在服务器上预取查询。这对于 SSG 很有用,如果你选择不使用 ssr: true,那么对于 SSR 也很有用。

¥The server-side helpers provides you with a set of helper functions that you can use to prefetch queries on the server. This is useful for SSG, but also for SSR if you opt not to use ssr: true.

通过服务器端辅助程序进行预取允许填充服务器上的查询缓存,这意味着这些查询最初不必在客户端上获取。

¥Prefetching via the server-side helpers allows populating the query cache on the server, which means that these queries do not have to fetch on the client initially.

有两种方法可以使用服务器端辅助程序。

¥There are 2 ways to use the server-side helpers.

1. 内部路由

¥ Internal router

当你可以直接访问 tRPC 路由时使用此方法。例如 开发单体 Next.js 应用时。

¥This method is used when you have direct access to your tRPC router. e.g. when developing a monolithic Next.js application.

使用辅助程序使 tRPC 直接在服务器上调用你的过程,无需 HTTP 请求,类似于 服务器端调用。这也意味着你手头没有像平常那样的请求和响应。确保使用没有 reqres 的上下文实例化服务器端辅助程序,这些上下文通常通过上下文创建来填充。在这种情况下我们推荐 "inner" 和 "outer" 上下文 的概念。

¥Using the helpers makes tRPC call your procedures directly on the server, without an HTTP request, similar to server-side calls. That also means that you don't have the request and response at hand like you usually do. Make sure you're instantiating the server-side helpers with a context without req & res, which are typically filled via the context creation. We recommend the concept of "inner" and "outer" context in that scenario.

ts
import { createServerSideHelpers } from '@trpc/react-query/server';
import { createContext } from '~/server/context';
import superjson from 'superjson';
const helpers = createServerSideHelpers({
router: appRouter,
ctx: await createContext(),
transformer: superjson, // optional - adds superjson serialization
});
ts
import { createServerSideHelpers } from '@trpc/react-query/server';
import { createContext } from '~/server/context';
import superjson from 'superjson';
const helpers = createServerSideHelpers({
router: appRouter,
ctx: await createContext(),
transformer: superjson, // optional - adds superjson serialization
});

2. 外部路由

¥ External router

当你无法直接访问 tRPC 路由时,可以使用此方法。例如 开发 Next.js 应用和单独托管的独立 API 时。

¥This method is used when you don't have direct access to your tRPC router. e.g. when developing a Next.js application and a standalone API hosted separately.

ts
import { createTRPCProxyClient } from '@trpc/client';
import { createServerSideHelpers } from '@trpc/react-query/server';
import superjson from 'superjson';
const proxyClient = createTRPCProxyClient<AppRouter>({
links: [
httpBatchLink({
url: 'http://localhost:3000/api/trpc',
}),
],
transformer: superjson,
});
const helpers = createServerSideHelpers({
client: proxyClient,
});
ts
import { createTRPCProxyClient } from '@trpc/client';
import { createServerSideHelpers } from '@trpc/react-query/server';
import superjson from 'superjson';
const proxyClient = createTRPCProxyClient<AppRouter>({
links: [
httpBatchLink({
url: 'http://localhost:3000/api/trpc',
}),
],
transformer: superjson,
});
const helpers = createServerSideHelpers({
client: proxyClient,
});

辅助程序的使用

¥Helpers usage

服务器端辅助程序方法返回一个与 tRPC 客户端非常相似的对象,以所有路由作为键。但是,你获得的不是 useQueryuseMutation,而是 prefetchfetchprefetchInfinitefetchInfinite 函数。

¥The server-side helpers methods return an object much like the tRPC client, with all of your routers as keys. However, rather than useQuery and useMutation, you get prefetch, fetch, prefetchInfinite, and fetchInfinite functions.

prefetchfetch 之间的主要区别在于 fetch 的行为很像普通函数调用,返回查询结果,而 prefetch 不返回结果并且从不抛出异常 - 如果你需要这种行为,请改用 fetch。相反,prefetch 会将查询添加到缓存中,然后将其脱水并发送到客户端。

¥The primary difference between prefetch and fetch is that fetch acts much like a normal function call, returning the result of the query, whereas prefetch does not return the result and never throws - if you need that behavior, use fetch instead. Instead, prefetch will add the query to the cache, which you then dehydrate and send to the client.

ts
return {
props: {
// very important - use `trpcState` as the key
trpcState: helpers.dehydrate(),
},
};
ts
return {
props: {
// very important - use `trpcState` as the key
trpcState: helpers.dehydrate(),
},
};

对于你知道在客户端上需要的查询,经验法则是 prefetch;对于你想要在服务器上使用其结果的查询,经验法则是 fetch

¥The rule of thumb is prefetch for queries that you know you'll need on the client, and fetch for queries that you want to use the result of on the server.

这些函数都是 react-query 函数的封装器。请查看 他们的文档 以详细了解它们。

¥The functions are all wrappers around react-query functions. Please check out their docs to learn more about them in detail.

信息

有关完整示例,请参阅我们的 端到端 SSG 测试示例

¥For a full example, see our E2E SSG test example

Next.js 示例

¥Next.js Example

pages/posts/[id].tsx
tsx
import { createServerSideHelpers } from '@trpc/react-query/server';
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
import { appRouter } from 'server/routers/_app';
import superjson from 'superjson';
import { trpc } from 'utils/trpc';
export async function getServerSideProps(
context: GetServerSidePropsContext<{ id: string }>,
) {
const helpers = createServerSideHelpers({
router: appRouter,
ctx: {},
transformer: superjson,
});
const id = context.params?.id as string;
/*
* Prefetching the `post.byId` query.
* `prefetch` does not return the result and never throws - if you need that behavior, use `fetch` instead.
*/
await helpers.post.byId.prefetch({ id });
// Make sure to return { props: { trpcState: helpers.dehydrate() } }
return {
props: {
trpcState: helpers.dehydrate(),
id,
},
};
}
export default function PostViewPage(
props: InferGetServerSidePropsType<typeof getServerSideProps>,
) {
const { id } = props;
const postQuery = trpc.post.byId.useQuery({ id });
if (postQuery.status !== 'success') {
// won't happen since the query has been prefetched
return <>Loading...</>;
}
const { data } = postQuery;
return (
<>
<h1>{data.title}</h1>
<em>Created {data.createdAt.toLocaleDateString()}</em>
<p>{data.text}</p>
<h2>Raw data:</h2>
<pre>{JSON.stringify(data, null, 4)}</pre>
</>
);
}
pages/posts/[id].tsx
tsx
import { createServerSideHelpers } from '@trpc/react-query/server';
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
import { appRouter } from 'server/routers/_app';
import superjson from 'superjson';
import { trpc } from 'utils/trpc';
export async function getServerSideProps(
context: GetServerSidePropsContext<{ id: string }>,
) {
const helpers = createServerSideHelpers({
router: appRouter,
ctx: {},
transformer: superjson,
});
const id = context.params?.id as string;
/*
* Prefetching the `post.byId` query.
* `prefetch` does not return the result and never throws - if you need that behavior, use `fetch` instead.
*/
await helpers.post.byId.prefetch({ id });
// Make sure to return { props: { trpcState: helpers.dehydrate() } }
return {
props: {
trpcState: helpers.dehydrate(),
id,
},
};
}
export default function PostViewPage(
props: InferGetServerSidePropsType<typeof getServerSideProps>,
) {
const { id } = props;
const postQuery = trpc.post.byId.useQuery({ id });
if (postQuery.status !== 'success') {
// won't happen since the query has been prefetched
return <>Loading...</>;
}
const { data } = postQuery;
return (
<>
<h1>{data.title}</h1>
<em>Created {data.createdAt.toLocaleDateString()}</em>
<p>{data.text}</p>
<h2>Raw data:</h2>
<pre>{JSON.stringify(data, null, 4)}</pre>
</>
);
}