服务端助手
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
服务端助手提供了一组辅助函数,可用于在服务器上预取查询。这对于 SSG(静态站点生成)非常有用,同时若您选择不使用 ssr: true,对 SSR(服务端渲染)也很有帮助。
通过服务端助手进行预取,可以在服务器端填充查询缓存,这意味着这些查询在客户端初始渲染时无需再次获取。
有两种使用服务端助手的方式
1. 内部路由
当您可以直接访问 tRPC 路由时使用此方法,例如在开发单体式 Next.js 应用时。
使用助手会使 tRPC 直接在服务器上调用您的操作过程,无需 HTTP 请求,类似于服务端调用。这也意味着您无法像通常那样访问请求(req)和响应(res)对象。请确保实例化服务端助手时使用不包含 req 和 res 的上下文(这些通常通过上下文创建过程填充)。在此场景下,我们推荐使用“内部”与“外部”上下文的概念。
tsimport { 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});
tsimport { 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 独立托管时。
tsimport { 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,});
tsimport { 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 客户端类似,包含您所有路由作为键名。但不同于 useQuery 和 useMutation,您将获得 prefetch、fetch、prefetchInfinite 和 fetchInfinite 函数。
prefetch 与 fetch 的核心区别在于:fetch 的行为类似普通函数调用,会返回查询结果;而 prefetch 不返回结果且永不抛出错误——若需要此行为,请改用 fetch。prefetch 会将查询加入缓存,后续通过脱水(dehydrate)操作发送至客户端。
tsreturn {props: {// very important - use `trpcState` as the keytrpcState: helpers.dehydrate(),},};
tsreturn {props: {// very important - use `trpcState` as the keytrpcState: helpers.dehydrate(),},};
经验法则是:对客户端需要使用的查询使用 prefetch,对需在服务端使用结果的查询使用 fetch。
这些函数都是 react-query 的封装器,请查阅其官方文档了解详细用法。
完整示例请参见我们的 E2E SSG 测试案例
Next.js 示例
pages/posts/[id].tsxtsximport { createServerSideHelpers } from '@trpc/react-query/server';import { appRouter } from '~/server/routers/_app';import { trpc } from '~/utils/trpc';import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';import superjson from 'superjson';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 prefetchedreturn <>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].tsxtsximport { createServerSideHelpers } from '@trpc/react-query/server';import { appRouter } from '~/server/routers/_app';import { trpc } from '~/utils/trpc';import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';import superjson from 'superjson';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 prefetchedreturn <>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></>);}