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 路由
在 ./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 参数,返回对象支持以下属性:
-
必须包含以下任一项:
url:API 地址links:自定义 tRPC 客户端与服务端数据流,详见
-
可选配置:
queryClientConfig:React Query 内部使用的QueryClient配置对象: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);