跳至主要内容
版本:11.x

服务器端助手

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

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

有两种方法可以使用服务器端助手。

1. 内部路由器

当您直接访问您的 tRPC 路由器时,使用此方法。例如,在开发单体 Next.js 应用程序时。

使用助手会使 tRPC 直接在服务器上调用您的过程,而无需 HTTP 请求,类似于 服务器端调用。这也意味着您没有像往常一样手头上的请求和响应。确保您使用没有 reqres 的上下文实例化服务器端助手,这些上下文通常通过上下文创建填充。我们建议在这种情况下使用 "内部" 和 "外部" 上下文 的概念。

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. 外部路由器

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

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

助手使用

服务器端助手方法返回一个类似于 tRPC 客户端的对象,其中所有路由器都作为键。但是,您获得的是 prefetchfetchprefetchInfinitefetchInfinite 函数,而不是 useQueryuseMutation

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

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

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

信息

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

Next.js 示例

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>
</>
);
}