본문 바로가기
버전: 9.x

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. 의존성 설치

bash
yarn add @trpc/client @trpc/server @trpc/react @trpc/next zod react-query@3
bash
yarn 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].ts
ts
import * 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 API
export type AppRouter = typeof appRouter;
// export API handler
export default trpcNext.createNextApiHandler({
router: appRouter,
createContext: () => null,
});
./pages/api/trpc/[trpc].ts
ts
import * 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 API
export type AppRouter = typeof appRouter;
// export API handler
export default trpcNext.createNextApiHandler({
router: appRouter,
createContext: () => null,
});

4. tRPC 훅 생성

API 타입 시그니처를 사용해 강력한 타입의 훅 세트를 생성하세요.

utils/trpc.ts
tsx
import { createReactQueryHooks } from '@trpc/react';
import type { AppRouter } from '../pages/api/trpc/[trpc]';
export const trpc = createReactQueryHooks<AppRouter>();
// => { useQuery: ..., useMutation: ...}
utils/trpc.ts
tsx
import { 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.tsx
tsx
import { 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.tsx
tsx
import { 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.tsx
tsx
import { 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.tsx
tsx
import { 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. 자세히 보기
  • 선택 사항:

    • queryClientConfig: tRPC React 훅에서 내부적으로 사용하는 React Query QueryClient에 대한 구성 객체. QueryClient 문서
    • headers: 발신 tRPC 요청의 객체를 반환하는 객체 또는 함수
    • transformer: 발신 페이로드에 적용되는 변환기. 데이터 변환기 참고
    • fetch: tRPC 내부에서 사용되는 fetch 구현 커스터마이즈
    • AbortController: tRPC 내부에서 사용되는 AbortController 구현 커스터마이즈

ssr-부울값 (기본값: false)

서버 사이드 렌더링 시 tRPC가 쿼리를 대기할지 여부. 기본값은 false입니다.

responseMeta-콜백

서버 사이드 렌더링 시 응답 헤더와 HTTP 상태 코드 설정 기능

예시

pages/_app.tsx
tsx
export default withTRPC<AppRouter>({
config(config) {
/* [...] */
},
ssr: true,
responseMeta({ clientErrors, ctx }) {
if (clientErrors.length) {
// propagate first http error from API calls
return {
status: clientErrors[0].data?.httpStatus ?? 500,
};
}
// cache full page for 1 day + revalidate once every second
const ONE_DAY_IN_SECONDS = 60 * 60 * 24;
return {
'Cache-Control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
};
},
})(MyApp);
pages/_app.tsx
tsx
export default withTRPC<AppRouter>({
config(config) {
/* [...] */
},
ssr: true,
responseMeta({ clientErrors, ctx }) {
if (clientErrors.length) {
// propagate first http error from API calls
return {
status: clientErrors[0].data?.httpStatus ?? 500,
};
}
// cache full page for 1 day + revalidate once every second
const ONE_DAY_IN_SECONDS = 60 * 60 * 24;
return {
'Cache-Control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
};
},
})(MyApp);

다음 단계

컴포넌트 내부에서 쿼리뮤테이션 실행에 대한 추가 정보는 @trpc/react 문서를 참조하세요.