Skip to main content
Version: 10.x

使用 Next.js 设置

¥Recommended file structure

我们推荐这样的文件结构,尽管它不是由 tRPC 强制执行的。这就是你将在 我们的例子 中看到的内容。本页的其余部分将引导你完成将 tRPC 添加到此结构的过程。

¥We recommend a file structure like this one, although it is not enforced by tRPC. This is what you'll see in our examples. The rest of this page will take you through the process of adding tRPC in to this structure.

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
└── [..]

将 tRPC 添加到现有的 Next.js 项目

¥Add tRPC to existing Next.js project

1. 安装依赖

¥ Install deps

sh
npm install @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query@4 zod
sh
npm install @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query@4 zod

Next.js 集成实际上是我们的 React 查询集成 和一些 Next.js 特定集成的组合。

¥The Next.js integration is actually a combination of our React Query Integration and some Next.js specific integrations.

2. 启用严格模式

¥ Enable strict mode

如果你想使用 Zod 进行输入验证,请确保你已在 tsconfig.json 中启用严格模式:

¥If you want to use Zod for input validation, make sure you have enabled strict mode in your tsconfig.json:

tsconfig.json
diff
"compilerOptions": {
+ "strict": true
}
tsconfig.json
diff
"compilerOptions": {
+ "strict": true
}

如果严格模式太苛刻,你至少要启用 strictNullChecks

¥If strict mode is too harsh, you'll at least want to enable strictNullChecks:

tsconfig.json
diff
"compilerOptions": {
+ "strictNullChecks": true
}
tsconfig.json
diff
"compilerOptions": {
+ "strictNullChecks": true
}

3. 创建 tRPC 路由

¥ Create a tRPC router

使用 initTRPC 函数在 src/server/trpc.ts 中初始化你的 tRPC 后端,并创建你的第一个路由。我们将在这里制作一个简单的 "你好世界" 路由和程序 - 但有关创建 tRPC API 的更深入信息,你应该参考:

¥Initialize your tRPC backend in src/server/trpc.ts using the initTRPC function, and create your first router. We're going to make a simple "hello world" router and procedure here - but for deeper information on creating your tRPC API you should refer to:

View sample backend
server/trpc.ts
ts
import { 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 helpers
export const router = t.router;
export const procedure = t.procedure;
server/trpc.ts
ts
import { 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 helpers
export const router = t.router;
export const procedure = t.procedure;

server/routers/_app.ts
ts
import { 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 API
export type AppRouter = typeof appRouter;
server/routers/_app.ts
ts
import { 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 API
export type AppRouter = typeof appRouter;

pages/api/trpc/[trpc].ts
ts
import * as trpcNext from '@trpc/server/adapters/next';
import { appRouter } from '../../../server/routers/_app';
// export API handler
// @see https://trpc.nodejs.cn/docs/server/adapters
export default trpcNext.createNextApiHandler({
router: appRouter,
createContext: () => ({}),
});
pages/api/trpc/[trpc].ts
ts
import * as trpcNext from '@trpc/server/adapters/next';
import { appRouter } from '../../../server/routers/_app';
// export API handler
// @see https://trpc.nodejs.cn/docs/server/adapters
export default trpcNext.createNextApiHandler({
router: appRouter,
createContext: () => ({}),
});
注意

上面的后端使用的是 推荐的文件结构,但如果你愿意,你可以保持简单并将所有内容放入 直接 API 处理程序

¥The backend above is using the recommended file structure, but you can keep it simple and put everything in an API handler directly if you prefer.

4. 创建 tRPC 钩子

¥ Create tRPC hooks

使用 createTRPCNext 函数根据 API 的类型签名创建一组强类型钩子。

¥use the createTRPCNext function to create a set of strongly-typed hooks from your API's type signature.

utils/trpc.ts
tsx
import { 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 path
return '';
if (process.env.VERCEL_URL)
// reference for vercel.com
return `https://${process.env.VERCEL_URL}`;
if (process.env.RENDER_INTERNAL_HOSTNAME)
// reference for render.com
return `http://${process.env.RENDER_INTERNAL_HOSTNAME}:${process.env.PORT}`;
// assume localhost
return `http://localhost:${process.env.PORT ?? 3000}`;
}
export const trpc = createTRPCNext<AppRouter>({
config(opts) {
return {
links: [
httpBatchLink({
/**
* If you want to use SSR, you need to use the server's full URL
* @link https://trpc.nodejs.cn/docs/ssr
**/
url: `${getBaseUrl()}/api/trpc`,
// You can pass any HTTP headers you wish here
async headers() {
return {
// authorization: getAuthCookie(),
};
},
}),
],
};
},
/**
* @link https://trpc.nodejs.cn/docs/ssr
**/
ssr: false,
});
utils/trpc.ts
tsx
import { 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 path
return '';
if (process.env.VERCEL_URL)
// reference for vercel.com
return `https://${process.env.VERCEL_URL}`;
if (process.env.RENDER_INTERNAL_HOSTNAME)
// reference for render.com
return `http://${process.env.RENDER_INTERNAL_HOSTNAME}:${process.env.PORT}`;
// assume localhost
return `http://localhost:${process.env.PORT ?? 3000}`;
}
export const trpc = createTRPCNext<AppRouter>({
config(opts) {
return {
links: [
httpBatchLink({
/**
* If you want to use SSR, you need to use the server's full URL
* @link https://trpc.nodejs.cn/docs/ssr
**/
url: `${getBaseUrl()}/api/trpc`,
// You can pass any HTTP headers you wish here
async headers() {
return {
// authorization: getAuthCookie(),
};
},
}),
],
};
},
/**
* @link https://trpc.nodejs.cn/docs/ssr
**/
ssr: false,
});
注意

createTRPCNext 不适用于 tRPC-v9 互操作模式。如果你使用互操作从 v9 迁移,则应继续使用 初始化 tRPC 的旧方法

¥createTRPCNext does not work with the tRPC-v9 interop mode. If you are migrating from v9 using interop, you should continue using the old way of initializing tRPC.

5. 配置 _app.tsx

¥ Configure _app.tsx

将你的根应用页面封装在 trpc.withTRPC HOC 中,类似于:

¥Wrap your root app page in the trpc.withTRPC HOC, similar to this:

pages/_app.tsx
tsx
import 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.tsx
tsx
import 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 请求

¥ Make an API request

你都准备好了!

¥You're all set!

你现在可以使用刚刚创建的 React hook 来调用 API。欲了解更多详情,请参阅 React 查询集成

¥You can now use the React hooks you have just created to invoke your API. For more detail see the React Query Integration

pages/index.tsx
tsx
import { 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.tsx
tsx
import { 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() 选项

¥createTRPCNext() options

config-回调

¥config-callback

config 参数是一个返回配置 tRPC 和 React Query 客户端的对象的函数。此函数有一个 ctx 输入,可让你访问 Next.js req 对象等。返回值可以包含以下属性:

¥The config-argument is a function that returns an object that configures the tRPC and React Query clients. This function has a ctx input that gives you access to the Next.js req object, among other things. The returned value can contain the following properties:

  • 必需的:

    ¥Required:

  • links 自定义 tRPC 客户端和 tRPC 服务器之间的数据流。阅读更多

    ¥links to customize the flow of data between tRPC Client and the tRPC Server. Read more.

  • 可选的:

    ¥Optional:

  • queryClientConfig:tRPC React hooks 在内部使用的 React Query QueryClient 的配置对象:查询客户端文档

    ¥queryClientConfig: a configuration object for the React Query QueryClient used internally by the tRPC React hooks: QueryClient docs

  • queryClient:React 查询 查询客户端实例

    ¥queryClient: a React Query QueryClient instance

    • 注意:你只能提供 queryClientqueryClientConfig

      ¥Note: You can only provide either a queryClient or a queryClientConfig.

  • transformer:应用于传出有效负载的转换器。了解有关 数据转换器 的更多信息

    ¥transformer: a transformer applied to outgoing payloads. Read more about Data Transformers

  • abortOnUnmount:确定是否在组件卸载时取消正在进行的请求。默认为 false

    ¥abortOnUnmount: determines if in-flight requests will be cancelled on component unmount. This defaults to false.

overrides:(默认:undefined

¥overrides: (default: undefined)

配置 覆盖 React Query 的钩子

¥Configure overrides for React Query's hooks.

ssr-布尔值(默认值:false

¥ssr-boolean (default: false)

服务器端渲染页面时 tRPC 是否应等待查询。默认为 false

¥Whether tRPC should await queries when server-side rendering a page. Defaults to false.

responseMeta-回调

¥responseMeta-callback

能够在服务器端渲染时设置请求标头和 HTTP 状态。

¥Ability to set request headers and HTTP status when server-side rendering.

示例

¥Example

utils/trpc.ts
tsx
import { createTRPCNext } from '@trpc/next';
import type { AppRouter } from '../pages/api/trpc/[trpc]';
export const trpc = createTRPCNext<AppRouter>({
config(opts) {
/* [...] */
},
ssr: true,
responseMeta(opts) {
const { clientErrors } = opts;
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}`,
};
},
});
utils/trpc.ts
tsx
import { createTRPCNext } from '@trpc/next';
import type { AppRouter } from '../pages/api/trpc/[trpc]';
export const trpc = createTRPCNext<AppRouter>({
config(opts) {
/* [...] */
},
ssr: true,
responseMeta(opts) {
const { clientErrors } = opts;
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}`,
};
},
});

下一步

¥Next steps

浏览其余文档以了解有关 authorizationmiddlewares错误处理 等内容的更多信息。

¥Browse the rest of the docs to learn more about things like authorization, middlewares, and error handling.

既然你正在使用 @trpc/react-query,你还可以找到有关 queriesmutations 的信息。

¥You can also find information about queries and mutations now that you're using @trpc/react-query.