Next.js와 함께 사용하기
이 페이지는 PageTurner AI로 번역되었습니다(베타). 프로젝트 공식 승인을 받지 않았습니다. 오류를 발견하셨나요? 문제 신고 →
새 프로젝트에서 tRPC를 사용한다면, 시작점이나 참고 자료로 예제 프로젝트 중 하나를 고려해 보세요: tRPC 예제 프로젝트
tRPC와 Next.js는 환상적인 조합입니다! Next.js를 사용하면 클라이언트와 서버를 단일 코드베이스에서 함께 구축하기 쉽습니다. 이는 양측 간 타입 공유를 간편하게 만듭니다.
tRPC는 Next.js 개발자 경험을 가능한 한 원활하게 만들기 위한 전용 도구를 포함하고 있습니다.
추천 파일 구조
권장하지만 강제되진 않는 파일 구조입니다. 예제에서 시작할 때 얻을 수 있는 구조입니다.
graphql.├── prisma # <-- if prisma is added│ └── [..]├── src│ ├── pages│ │ ├── _app.tsx # <-- add `withTRPC()`-HOC here│ │ ├── api│ │ │ └── trpc│ │ │ └── [trpc].ts # <-- tRPC HTTP handler│ │ └── [..]│ ├── server│ │ ├── routers│ │ │ ├── app.ts # <-- main app router│ │ │ ├── post.ts # <-- sub routers│ │ │ └── [..]│ │ ├── context.ts # <-- create app context│ │ └── createRouter.ts # <-- router helper│ └── utils│ └── trpc.ts # <-- your typesafe tRPC hooks└── [..]
graphql.├── prisma # <-- if prisma is added│ └── [..]├── src│ ├── pages│ │ ├── _app.tsx # <-- add `withTRPC()`-HOC here│ │ ├── api│ │ │ └── trpc│ │ │ └── [trpc].ts # <-- tRPC HTTP handler│ │ └── [..]│ ├── server│ │ ├── routers│ │ │ ├── app.ts # <-- main app router│ │ │ ├── post.ts # <-- sub routers│ │ │ └── [..]│ │ ├── context.ts # <-- create app context│ │ └── createRouter.ts # <-- router helper│ └── utils│ └── trpc.ts # <-- your typesafe tRPC hooks└── [..]
기존 Next.js 프로젝트에 tRPC 추가하기
1. 의존성 설치
bashyarn add @trpc/client @trpc/server @trpc/react @trpc/next zod react-query@3
bashyarn add @trpc/client @trpc/server @trpc/react @trpc/next zod react-query@3
-
React Query:
@trpc/react는 @tanstack/react-query 위에 얇은 레이어를 제공합니다. peer dependency로 필수입니다. -
Zod: 대부분의 예제는 입력 검증을 위해 Zod를 사용하며 권장하지만 필수는 아닙니다. 선호하는 검증 라이브러리(Yup, Superstruct, io-ts 등)를 사용할 수 있습니다. 실제로
parse,create또는validateSync메서드를 포함하는 모든 객체가 작동합니다.
2. 엄격 모드 활성화
Zod를 입력 유효성 검사에 사용하려면 tsconfig.json에서 엄격 모드를 활성화해야 합니다:
json// tsconfig.json{// ..."compilerOptions": {// ..."strict": true}}
json// tsconfig.json{// ..."compilerOptions": {// ..."strict": true}}
엄격 모드가 부담스러울 경우 최소한 strictNullChecks는 활성화하세요:
json// tsconfig.json{// ..."compilerOptions": {// ..."strictNullChecks": true}}
json// tsconfig.json{// ..."compilerOptions": {// ..."strictNullChecks": true}}
3. tRPC 라우터 생성
tRPC 라우터를 ./pages/api/trpc/[trpc].ts에 구현하세요. 라우터를 여러 하위 라우터로 분할해야 한다면, 프로젝트 루트의 최상위 server 디렉터리에 구현한 후 ./pages/api/trpc/[trpc].ts로 가져와 단일 루트 appRouter로 병합하세요.
View sample router
./pages/api/trpc/[trpc].tstsimport * as trpc from '@trpc/server';import * as trpcNext from '@trpc/server/adapters/next';import { z } from 'zod';export const appRouter = trpc.router().query('hello', {input: z.object({text: z.string().nullish(),}).nullish(),resolve({ input }) {return {greeting: `hello ${input?.text ?? 'world'}`,};},});// export type definition of APIexport type AppRouter = typeof appRouter;// export API handlerexport default trpcNext.createNextApiHandler({router: appRouter,createContext: () => null,});
./pages/api/trpc/[trpc].tstsimport * as trpc from '@trpc/server';import * as trpcNext from '@trpc/server/adapters/next';import { z } from 'zod';export const appRouter = trpc.router().query('hello', {input: z.object({text: z.string().nullish(),}).nullish(),resolve({ input }) {return {greeting: `hello ${input?.text ?? 'world'}`,};},});// export type definition of APIexport type AppRouter = typeof appRouter;// export API handlerexport default trpcNext.createNextApiHandler({router: appRouter,createContext: () => null,});
4. tRPC 훅 생성
API 타입 시그니처를 사용해 강력한 타입의 훅 세트를 생성하세요.
utils/trpc.tstsximport { createReactQueryHooks } from '@trpc/react';import type { AppRouter } from '../pages/api/trpc/[trpc]';export const trpc = createReactQueryHooks<AppRouter>();// => { useQuery: ..., useMutation: ...}
utils/trpc.tstsximport { createReactQueryHooks } from '@trpc/react';import type { AppRouter } from '../pages/api/trpc/[trpc]';export const trpc = createReactQueryHooks<AppRouter>();// => { useQuery: ..., useMutation: ...}
5. _app.tsx 설정
createReactQueryHooks 함수는 Context API를 통해 특정 매개변수가 전달되기를 기대합니다. 이 매개변수를 설정하려면 withTRPC 고차 컴포넌트를 사용해 커스텀 _app.tsx를 생성하세요:
pages/_app.tsxtsximport { withTRPC } from '@trpc/next';import { AppType } from 'next/dist/shared/lib/utils';import type { AppRouter } from './api/trpc/[trpc]';const MyApp: AppType = ({ Component, pageProps }) => {return <Component {...pageProps} />;};export default withTRPC<AppRouter>({config(config) {/*** If you want to use SSR, you need to use the server's full URL* @see https://trpc.io/docs/ssr*/const url = process.env.VERCEL_URL? `https://${process.env.VERCEL_URL}/api/trpc`: 'http://localhost:3000/api/trpc';return {url,/*** @see https://tanstack.com/query/v3/docs/react/reference/QueryClient*/// queryClientConfig: { defaultOptions: { queries: { staleTime: 60 } } },};},/*** @see https://trpc.io/docs/ssr*/ssr: true,})(MyApp);
pages/_app.tsxtsximport { withTRPC } from '@trpc/next';import { AppType } from 'next/dist/shared/lib/utils';import type { AppRouter } from './api/trpc/[trpc]';const MyApp: AppType = ({ Component, pageProps }) => {return <Component {...pageProps} />;};export default withTRPC<AppRouter>({config(config) {/*** If you want to use SSR, you need to use the server's full URL* @see https://trpc.io/docs/ssr*/const url = process.env.VERCEL_URL? `https://${process.env.VERCEL_URL}/api/trpc`: 'http://localhost:3000/api/trpc';return {url,/*** @see https://tanstack.com/query/v3/docs/react/reference/QueryClient*/// queryClientConfig: { defaultOptions: { queries: { staleTime: 60 } } },};},/*** @see https://trpc.io/docs/ssr*/ssr: true,})(MyApp);
6. API 요청 수행
pages/index.tsxtsximport { trpc } from '../utils/trpc';export default function IndexPage() {const hello = trpc.useQuery(['hello', { text: 'client' }]);if (!hello.data) {return <div>Loading...</div>;}return (<div><p>{hello.data.greeting}</p></div>);}
pages/index.tsxtsximport { trpc } from '../utils/trpc';export default function IndexPage() {const hello = trpc.useQuery(['hello', { text: 'client' }]);if (!hello.data) {return <div>Loading...</div>;}return (<div><p>{hello.data.greeting}</p></div>);}
withTRPC() 옵션
config 콜백
config 인수는 tRPC 및 React Query 클라이언트를 구성하는 객체를 반환하는 함수입니다. 이 함수는 Next.js req 객체 등에 접근할 수 있는 ctx 입력을 받습니다. 반환된 객체는 다음 속성을 포함할 수 있습니다:
-
다음 중 정확히 하나가 필수입니다:
- API URL인
url - tRPC 클라이언트와 tRPC 서버 간 데이터 흐름을 커스터마이즈하는
links. 자세히 보기
- API URL인
-
선택 사항:
queryClientConfig: tRPC React 훅에서 내부적으로 사용하는 React QueryQueryClient에 대한 구성 객체. QueryClient 문서headers: 발신 tRPC 요청의 객체를 반환하는 객체 또는 함수transformer: 발신 페이로드에 적용되는 변환기. 데이터 변환기 참고fetch: tRPC 내부에서 사용되는fetch구현 커스터마이즈AbortController: tRPC 내부에서 사용되는AbortController구현 커스터마이즈
ssr-부울값 (기본값: false)
서버 사이드 렌더링 시 tRPC가 쿼리를 대기할지 여부. 기본값은 false입니다.
responseMeta-콜백
서버 사이드 렌더링 시 응답 헤더와 HTTP 상태 코드 설정 기능
예시
pages/_app.tsxtsxexport default withTRPC<AppRouter>({config(config) {/* [...] */},ssr: true,responseMeta({ clientErrors, ctx }) {if (clientErrors.length) {// propagate first http error from API callsreturn {status: clientErrors[0].data?.httpStatus ?? 500,};}// cache full page for 1 day + revalidate once every secondconst ONE_DAY_IN_SECONDS = 60 * 60 * 24;return {'Cache-Control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,};},})(MyApp);
pages/_app.tsxtsxexport default withTRPC<AppRouter>({config(config) {/* [...] */},ssr: true,responseMeta({ clientErrors, ctx }) {if (clientErrors.length) {// propagate first http error from API callsreturn {status: clientErrors[0].data?.httpStatus ?? 500,};}// cache full page for 1 day + revalidate once every secondconst ONE_DAY_IN_SECONDS = 60 * 60 * 24;return {'Cache-Control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,};},})(MyApp);