服务器端助手
服务器端助手为您提供了一组助手函数,您可以使用它们在服务器上预取查询。这对于 SSG 很有用,但如果您选择不使用 ssr: true
,则对于 SSR 也很有用。
通过服务器端助手进行预取允许在服务器上填充查询缓存,这意味着这些查询最初不需要在客户端上获取。
有两种方法可以使用服务器端助手。
1. 内部路由器
当您直接访问您的 tRPC 路由器时,使用此方法。例如,在开发单体 Next.js 应用程序时。
使用助手会使 tRPC 直接在服务器上调用您的过程,而无需 HTTP 请求,类似于 服务器端调用。这也意味着您没有像往常一样手头上的请求和响应。确保您使用没有 req
和 res
的上下文实例化服务器端助手,这些上下文通常通过上下文创建填充。我们建议在这种情况下使用 "内部" 和 "外部" 上下文 的概念。
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 客户端的对象,其中所有路由器都作为键。但是,您获得的是 prefetch
、fetch
、prefetchInfinite
和 fetchInfinite
函数,而不是 useQuery
和 useMutation
。
prefetch
和 fetch
之间的主要区别在于 fetch
的行为更像一个正常的函数调用,返回查询的结果,而 prefetch
不会返回结果并且永远不会抛出异常 - 如果您需要这种行为,请使用 fetch
。相反,prefetch
会将查询添加到缓存中,然后您将其脱水并发送到客户端。
ts
return {props: {// very important - use `trpcState` as the keytrpcState: helpers.dehydrate(),},};
ts
return {props: {// very important - use `trpcState` as the keytrpcState: helpers.dehydrate(),},};
经验法则是,对于您知道将在客户端上需要的查询,使用 prefetch
,对于您想要在服务器上使用结果的查询,使用 fetch
。
这些函数都是围绕 react-query 函数的包装器。请查看 他们的文档 以详细了解它们。
有关完整示例,请参阅我们的 E2E SSG 测试示例
Next.js 示例
pages/posts/[id].tsxtsx
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 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].tsxtsx
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 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></>);}