Next.jsでのセットアップ
このページは PageTurner AI で翻訳されました(ベータ版)。プロジェクト公式の承認はありません。 エラーを見つけましたか? 問題を報告 →
推奨ファイル構造
tRPCで強制されるものではありませんが、以下のようなファイル構造を推奨します。これはサンプルアプリケーションで確認できる構成です。このページでは、この構造にtRPCを追加する手順を説明します。
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│ │ └── trpc.ts # <-- procedure helpers│ └── 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│ │ └── trpc.ts # <-- procedure helpers│ └── utils│ └── trpc.ts # <-- your typesafe tRPC hooks└── [..]
既存のNext.jsプロジェクトにtRPCを追加
1. 依存関係のインストール
- npm
- yarn
- pnpm
- bun
shnpm install @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query@4 zod
shnpm install @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query@4 zod
shyarn add @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query@4 zod
shyarn add @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query@4 zod
shpnpm add @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query@4 zod
shpnpm add @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query@4 zod
shbun add @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query@4 zod
shbun add @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query@4 zod
Next.js連携機能は、React Query連携とNext.js固有の統合機能を組み合わせたものです。
2. 厳格モードを有効化
Zodを使用した入力検証を行う場合は、tsconfig.jsonで厳格モード(strict mode)を有効化してください:
tsconfig.jsondiff"compilerOptions": {+ "strict": true}
tsconfig.jsondiff"compilerOptions": {+ "strict": true}
厳格モードが厳しすぎる場合は、少なくともstrictNullChecksを有効化することを推奨します:
tsconfig.jsondiff"compilerOptions": {+ "strictNullChecks": true}
tsconfig.jsondiff"compilerOptions": {+ "strictNullChecks": true}
3. tRPCルーターを作成
src/server/trpc.tsでinitTRPC関数を使用してtRPCバックエンドを初期化し、最初のルーターを作成します。ここではシンプルな「hello world」ルーターとプロシージャを作成します。tRPC APIの詳細な作成方法については以下を参照してください:
-
tRPCの基本情報: クイックスタートガイドとバックエンド利用ドキュメント
-
Next.jsサーバー内でのtRPC実装方法: Next.jsアダプタードキュメント
View sample backend
server/trpc.tstsimport { initTRPC } from '@trpc/server';// Avoid exporting the entire t-object// since it's not very descriptive.// For instance, the use of a t variable// is common in i18n libraries.const t = initTRPC.create();// Base router and procedure helpersexport const router = t.router;export const procedure = t.procedure;
server/trpc.tstsimport { initTRPC } from '@trpc/server';// Avoid exporting the entire t-object// since it's not very descriptive.// For instance, the use of a t variable// is common in i18n libraries.const t = initTRPC.create();// Base router and procedure helpersexport const router = t.router;export const procedure = t.procedure;
server/routers/_app.tstsimport { z } from 'zod';import { procedure, router } from '../trpc';export const appRouter = router({hello: procedure.input(z.object({text: z.string(),}),).query((opts) => {return {greeting: `hello ${opts.input.text}`,};}),});// export type definition of APIexport type AppRouter = typeof appRouter;
server/routers/_app.tstsimport { z } from 'zod';import { procedure, router } from '../trpc';export const appRouter = router({hello: procedure.input(z.object({text: z.string(),}),).query((opts) => {return {greeting: `hello ${opts.input.text}`,};}),});// export type definition of APIexport type AppRouter = typeof appRouter;
pages/api/trpc/[trpc].tstsimport * as trpcNext from '@trpc/server/adapters/next';import { appRouter } from '../../../server/routers/_app';// export API handler// @link https://trpc.io/docs/server/adaptersexport default trpcNext.createNextApiHandler({router: appRouter,createContext: () => ({}),});
pages/api/trpc/[trpc].tstsimport * as trpcNext from '@trpc/server/adapters/next';import { appRouter } from '../../../server/routers/_app';// export API handler// @link https://trpc.io/docs/server/adaptersexport default trpcNext.createNextApiHandler({router: appRouter,createContext: () => ({}),});
上記のバックエンドは推奨ファイル構造を使用していますが、簡略化してAPIハンドラー内に直接実装することも可能です。
4. tRPCフックを作成
createTRPCNext関数を使用して、APIの型シグネチャから厳密に型付けされたフックセットを作成します。
utils/trpc.tstsximport { httpBatchLink } from '@trpc/client';import { createTRPCNext } from '@trpc/next';import type { AppRouter } from '../server/routers/_app';function getBaseUrl() {if (typeof window !== 'undefined')// browser should use relative pathreturn '';if (process.env.VERCEL_URL)// reference for vercel.comreturn `https://${process.env.VERCEL_URL}`;if (process.env.RENDER_INTERNAL_HOSTNAME)// reference for render.comreturn `http://${process.env.RENDER_INTERNAL_HOSTNAME}:${process.env.PORT}`;// assume localhostreturn `http://localhost:${process.env.PORT ?? 3000}`;}export const trpc = createTRPCNext<AppRouter>({config(config) {return {links: [httpBatchLink({/*** If you want to use SSR, you need to use the server's full URL* @see https://trpc.io/docs/ssr**/url: `${getBaseUrl()}/api/trpc`,// You can pass any HTTP headers you wish hereasync headers() {return {// authorization: getAuthCookie(),};},}),],};},/*** @see https://trpc.io/docs/ssr**/ssr: false,});
utils/trpc.tstsximport { httpBatchLink } from '@trpc/client';import { createTRPCNext } from '@trpc/next';import type { AppRouter } from '../server/routers/_app';function getBaseUrl() {if (typeof window !== 'undefined')// browser should use relative pathreturn '';if (process.env.VERCEL_URL)// reference for vercel.comreturn `https://${process.env.VERCEL_URL}`;if (process.env.RENDER_INTERNAL_HOSTNAME)// reference for render.comreturn `http://${process.env.RENDER_INTERNAL_HOSTNAME}:${process.env.PORT}`;// assume localhostreturn `http://localhost:${process.env.PORT ?? 3000}`;}export const trpc = createTRPCNext<AppRouter>({config(config) {return {links: [httpBatchLink({/*** If you want to use SSR, you need to use the server's full URL* @see https://trpc.io/docs/ssr**/url: `${getBaseUrl()}/api/trpc`,// You can pass any HTTP headers you wish hereasync headers() {return {// authorization: getAuthCookie(),};},}),],};},/*** @see https://trpc.io/docs/ssr**/ssr: false,});
createTRPCNextはtRPC-v9の互換モードでは動作しません。v9から移行中で互換モードを使用している場合は、tRPCフックの初期化の旧方式を引き続き使用してください。
5. _app.tsxを設定
ルートアプリページを以下のようにtrpc.withTRPC HOCでラップします:
pages/_app.tsxtsximport type { AppType } from 'next/app';import { trpc } from '../utils/trpc';const MyApp: AppType = ({ Component, pageProps }) => {return <Component {...pageProps} />;};export default trpc.withTRPC(MyApp);
pages/_app.tsxtsximport type { AppType } from 'next/app';import { trpc } from '../utils/trpc';const MyApp: AppType = ({ Component, pageProps }) => {return <Component {...pageProps} />;};export default trpc.withTRPC(MyApp);
6. APIリクエストを実行
これで準備完了です!
作成したReactフックを使用してAPIを呼び出せるようになりました。詳細はReact Query連携を参照してください。
pages/index.tsxtsximport { trpc } from '../utils/trpc';export default function IndexPage() {const hello = trpc.hello.useQuery({ 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.hello.useQuery({ text: 'client' });if (!hello.data) {return <div>Loading...</div>;}return (<div><p>{hello.data.greeting}</p></div>);}
createTRPCNext()のオプション
configコールバック
config引数はtRPCおよびReact Queryクライアントを設定するオブジェクトを返す関数です。この関数はNext.jsのreqオブジェクトなどにアクセスできるctx入力を受け取り、以下のプロパティを含むオブジェクトを返します:
-
必須:
-
tRPCクライアントとサーバー間のデータフローをカスタマイズする
links:詳細 -
任意:
-
queryClientConfig: tRPC Reactフックが内部的に使用するReact QueryのQueryClientの設定オブジェクト: QueryClientドキュメント -
queryClient: React QueryのQueryClientインスタンス- 注意:
queryClientとqueryClientConfigのどちらか一方のみを指定できます。
- 注意:
-
transformer: 送信ペイロードに適用するトランスフォーマー。データトランスフォーマーに関する詳細 -
abortOnUnmount: コンポーネントのアンマウント時に処理中のリクエストをキャンセルするかどうか。デフォルトはfalseです。
overrides: (デフォルト: undefined)
ssr-boolean (デフォルト: false)
サーバーサイドレンダリング時にtRPCがクエリを待機するかどうか。デフォルトはfalseです。
responseMeta-コールバック
サーバーサイドレンダリング時のリクエストヘッダーとHTTPステータスの設定
使用例
utils/trpc.tstsximport { createTRPCNext } from '@trpc/next';import type { AppRouter } from '../pages/api/trpc/[trpc]';export const trpc = createTRPCNext<AppRouter>({config(config) {/* [...] */},ssr: true,responseMeta(opts) {const { clientErrors } = opts;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}`,};},});
utils/trpc.tstsximport { createTRPCNext } from '@trpc/next';import type { AppRouter } from '../pages/api/trpc/[trpc]';export const trpc = createTRPCNext<AppRouter>({config(config) {/* [...] */},ssr: true,responseMeta(opts) {const { clientErrors } = opts;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}`,};},});