서버 사이드 헬퍼
이 페이지는 PageTurner AI로 번역되었습니다(베타). 프로젝트 공식 승인을 받지 않았습니다. 오류를 발견하셨나요? 문제 신고 →
서버 사이드 헬퍼는 서버에서 쿼리를 미리 가져오기(prefetch) 위해 사용할 수 있는 헬퍼 함수 세트를 제공합니다. 이는 SSG(Static Site Generation)에 유용하며, ssr: true를 사용하지 않기로 선택한 경우 SSR(Server-Side Rendering)에도 유용합니다.
서버 사이드 헬퍼를 통한 미리 가져오기(prefetching)는 서버에서 쿼리 캐시를 채울 수 있게 해주며, 이는 이러한 쿼리가 클라이언트에서 초기에 가져올 필요가 없음을 의미합니다.
서버 사이드 헬퍼 사용에는 두 가지 방법이 있습니다.
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 { 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,});
tsimport { 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,});
헬퍼 사용법
서버 사이드 헬퍼 메서드는 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 함수를 기반으로 한 래퍼(wrapper)입니다. 자세한 내용은 공식 문서를 참조하세요.
전체 예제는 E2E SSG 테스트 예제를 참조하세요.
Next.js 예제
pages/posts/[id].tsxtsximport { 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].tsxtsximport { 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></>);}