跳至主内容
版本: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 中启用严格模式:

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].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 地址
    • links:自定义 tRPC 客户端与服务端数据流,详见
  • 可选配置:

    • queryClientConfig: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 文档。