服务端助手
本页面由 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 {appRouter } from './server/routers/_app';importsuperjson from 'superjson';consthelpers =createServerSideHelpers ({router :appRouter ,ctx : awaitcreateContext (),transformer :superjson ,});
tsimport {createServerSideHelpers } from '@trpc/react-query/server';import {createContext } from './server/context';import {appRouter } from './server/routers/_app';importsuperjson from 'superjson';consthelpers =createServerSideHelpers ({router :appRouter ,ctx : awaitcreateContext (),transformer :superjson ,});
2. 外部路由
当您无法直接访问 tRPC 路由器时(例如 Next.js 应用与独立部署的 API 分开开发),可使用此方法。
tsimport {createTRPCClient ,httpBatchLink } from '@trpc/client';import {createServerSideHelpers } from '@trpc/react-query/server';import type {AppRouter } from './server/router';importsuperjson from 'superjson';constproxyClient =createTRPCClient <AppRouter >({links : [httpBatchLink ({url : 'http://localhost:3000/api/trpc',}),],});consthelpers =createServerSideHelpers ({client :proxyClient ,});
tsimport {createTRPCClient ,httpBatchLink } from '@trpc/client';import {createServerSideHelpers } from '@trpc/react-query/server';import type {AppRouter } from './server/router';importsuperjson from 'superjson';constproxyClient =createTRPCClient <AppRouter >({links : [httpBatchLink ({url : 'http://localhost:3000/api/trpc',}),],});consthelpers =createServerSideHelpers ({client :proxyClient ,});
助手使用方法
服务端助手方法返回的对象会镜像您的路由器结构,所有路由均作为键名呈现。但与 useQuery 和 useMutation 不同,您将获得 prefetch、fetch、prefetchInfinite 和 fetchInfinite 函数。
prefetch 与 fetch 的核心区别在于:fetch 的行为类似普通函数调用,会返回查询结果;而 prefetch 不返回结果且永不抛出错误——若需要此行为,请改用 fetch。prefetch 会将查询加入缓存,后续通过脱水(dehydrate)操作发送至客户端。
ts// In getServerSideProps / getStaticProps:constprops = {// very important - use `trpcState` as the keytrpcState :helpers .dehydrate (),};
ts// In getServerSideProps / getStaticProps:constprops = {// 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';importsuperjson from 'superjson';export async functiongetServerSideProps (context :GetServerSidePropsContext <{id : string }>,) {consthelpers =createServerSideHelpers ({router :appRouter ,ctx : {},transformer :superjson ,});constid =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.*/awaithelpers .post .byId .prefetch ({id });// Make sure to return { props: { trpcState: helpers.dehydrate() } }return {props : {trpcState :helpers .dehydrate (),id ,},};}export default functionPostViewPage (props :InferGetServerSidePropsType <typeofgetServerSideProps >,) {const {id } =props ;constpostQuery =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';importsuperjson from 'superjson';export async functiongetServerSideProps (context :GetServerSidePropsContext <{id : string }>,) {consthelpers =createServerSideHelpers ({router :appRouter ,ctx : {},transformer :superjson ,});constid =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.*/awaithelpers .post .byId .prefetch ({id });// Make sure to return { props: { trpcState: helpers.dehydrate() } }return {props : {trpcState :helpers .dehydrate (),id ,},};}export default functionPostViewPage (props :InferGetServerSidePropsType <typeofgetServerSideProps >,) {const {id } =props ;constpostQuery =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 ></>);}