メインコンテンツへスキップ
バージョン: 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を使用しており、必須ではありませんが強く推奨します。お好みの検証ライブラリ(YupSuperstructio-tsなど)も使用可能です。実際、parsecreatevalidateSyncメソッドを含むオブジェクトであれば動作します

2. 厳格モードを有効化

Zodを使用した入力検証を行う場合は、tsconfig.jsonで厳格モード(strict mode)を有効化してください:

json
// tsconfig.json
{
// ...
"compilerOptions": {
// ...
"strict": true
}
}
json
// tsconfig.json
{
// ...
"compilerOptions": {
// ...
"strict": true
}
}

厳格モード(strict mode)が厳しすぎる場合は、少なくとも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入力を受け取り、以下のプロパティを含むオブジェクトを返します:

  • 以下のいずれか一つが必須です:

    • url: APIのURL
    • links: tRPCクライアントとtRPCサーバー間のデータフローをカスタマイズするリンク。詳細
  • オプション:

    • queryClientConfig: tRPC Reactフック内部で使用されるReact QueryのQueryClient設定オブジェクト。QueryClientドキュメント
    • headers: 送信tRPCリクエストのヘッダーオブジェクト、またはヘッダーオブジェクトを返す関数
    • transformer: 送信ペイロードに適用するトランスフォーマー。データトランスフォーマーを参照
    • fetch: tRPC内部で使用されるfetchの実装をカスタマイズ
    • AbortController: tRPC内部で使用されるAbortControllerの実装をカスタマイズ

ssr-boolean (デフォルト: 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ドキュメントを参照してください。