Skip to main content
Version: 10.x

链接概述

链接使你能够自定义 tRPC 客户端和服务器之间的数据流。链接应该只做一件事,这可以是对 tRPC 操作(查询、突变或订阅)的独立修改,也可以是基于操作的副作用(例如日志记录)。

¥Links enable you to customize the flow of data between the tRPC Client and Server. A link should do only one thing, which can be either a self-contained modification to a tRPC operation (query, mutation, or subscription) or a side-effect based on the operation (such as logging).

你可以将链接组合在一起形成一个数组,你可以通过代表链接链的 links 属性将其提供给 tRPC 客户端配置。这意味着 tRPC 客户端将在执行请求时按照添加到 links 数组的顺序执行链接,并在处理响应时以相反的顺序再次执行它们。这是链接链的直观表示:

¥You can compose links together into an array that you can provide to the tRPC client configuration via the links property, which represents a link chain. This means that the tRPC client will execute the links in the order they are added to the links array when doing a request and will execute them again in reverse when it's handling a response. Here's a visual representation of the link chain:

tRPC Link DiagramtRPC Link Diagram. Based on Apollo's.
注意

以下示例假设你使用 Next.js,但如果你使用 vanilla tRPC 客户端,则可以添加与下面相同的内容

¥The below examples are assuming you use Next.js, but the same as below can be added if you use the vanilla tRPC client

utils/trpc.ts
tsx
import { httpBatchLink, loggerLink } from '@trpc/client';
import { createTRPCNext } from '@trpc/next';
export default createTRPCNext<AppRouter>({
config() {
const url = `http://localhost:3000`;
return {
links: [
loggerLink(),
httpBatchLink({
url,
}),
],
};
},
});
utils/trpc.ts
tsx
import { httpBatchLink, loggerLink } from '@trpc/client';
import { createTRPCNext } from '@trpc/next';
export default createTRPCNext<AppRouter>({
config() {
const url = `http://localhost:3000`;
return {
links: [
loggerLink(),
httpBatchLink({
url,
}),
],
};
},
});

¥Creating a custom link

链接是遵循 TRPCLink 类型的函数。每个链接由三部分组成:

¥A link is a function that follows the TRPCLink type. Each link is composed of three parts:

  1. 该链接返回一个具有 TRPCClientRuntime 类型参数的函数。该参数由 tRPC 传递,并在创建 终止链接 时使用。如果你不创建终止链接,则可以只创建一个没有参数的函数。在这种情况下,应将链接添加到 links 数组而不调用 (links: [..., myLink, httpBatchLink(...)])。

    ¥The link returns a function that has a parameter with the TRPCClientRuntime type. This argument is passed by tRPC and it is used when creating a terminating link. If you're not creating a terminating link, you can just create a function that has no parameters. In such case, the link should be added to the links array without invoking (links: [..., myLink, httpBatchLink(...)]).

  2. 步骤 1 中的函数返回另一个函数,该函数接收具有两个属性的对象:op 是客户端正在执行的 Operationnext 是我们用来调用链上下一个链接的函数。

    ¥The function in step 1 returns another function that receives an object with two properties: op which is the Operation that is being executed by the client, and next which is the function we use to call the next link down the chain.

  3. 步骤 2 中的函数返回最终函数,该函数返回 @trpc/server 提供的 observable 函数。observable 接受一个接收 observer 的函数,这有助于我们的链接通知链上的下一个链接它们应该如何处理操作结果。在这个函数中,我们可以只返回 next(op) 并保持原样,或者我们可以订阅 next,这使得我们的链接能够处理操作结果。

    ¥The function in step 2 returns a final function that returns the observable function provided by @trpc/server. The observable accepts a function that receives an observer which helps our link notify the next link up the chain how they should handle the operation result. In this function, we can just return next(op) and leave it as is, or we can subscribe to next, which enables our link to handle the operation result.

示例

¥Example

utils/customLink.ts
tsx
import { TRPCLink } from '@trpc/client';
import { observable } from '@trpc/server/observable';
import type { AppRouter } from 'server/routers/_app';
export const customLink: TRPCLink<AppRouter> = () => {
// here we just got initialized in the app - this happens once per app
// useful for storing cache for instance
return ({ next, op }) => {
// this is when passing the result to the next link
// each link needs to return an observable which propagates results
return observable((observer) => {
console.log('performing operation:', op);
const unsubscribe = next(op).subscribe({
next(value) {
console.log('we received value', value);
observer.next(value);
},
error(err) {
console.log('we received error', err);
observer.error(err);
},
complete() {
observer.complete();
},
});
return unsubscribe;
});
};
};
utils/customLink.ts
tsx
import { TRPCLink } from '@trpc/client';
import { observable } from '@trpc/server/observable';
import type { AppRouter } from 'server/routers/_app';
export const customLink: TRPCLink<AppRouter> = () => {
// here we just got initialized in the app - this happens once per app
// useful for storing cache for instance
return ({ next, op }) => {
// this is when passing the result to the next link
// each link needs to return an observable which propagates results
return observable((observer) => {
console.log('performing operation:', op);
const unsubscribe = next(op).subscribe({
next(value) {
console.log('we received value', value);
observer.next(value);
},
error(err) {
console.log('we received error', err);
observer.error(err);
},
complete() {
observer.complete();
},
});
return unsubscribe;
});
};
};

参考

¥References

如果你需要更真实的参考来创建自定义链接,你可以查看 tRPC 在 GitHub 上提供的一些内置链接。

¥If you need a more real reference for creating your custom link, you can check out some of the built-in links tRPC provides on GitHub.

¥The terminating link

终止链接是链接链中的最后一个链接。终止链接负责将你组合的 tRPC 操作发送到 tRPC 服务器并返回 OperationResultEnvelope,而不是调用 next 函数。

¥The terminating link is the last link in a link chain. Instead of calling the next function, the terminating link is responsible for sending your composed tRPC operation to the tRPC server and returning an OperationResultEnvelope.

添加到 tRPC 客户端配置的 links 数组应该至少有一个链接,并且该链接应该是终止链接。如果 links 的末尾没有终止链接,则 tRPC 操作将不会发送到 tRPC 服务器。

¥The links array that you add to the tRPC client config should have at least one link, and that link should be a terminating link. If links don't have a terminating link at the end of them, the tRPC operation will not be sent to the tRPC server.

httpBatchLink 是 tRPC 推荐的终止链接。

¥httpBatchLink is the recommended terminating link by tRPC.

httpLinkwsLink 是终止链路的其他示例。

¥httpLink and wsLink are other examples of terminating links.

管理环境

¥Managing context

当操作沿着链接链移动时,它会维护每个链接都可以读取和修改的上下文。这允许链接沿着其他链接在其执行逻辑中使用的链传递元数据。

¥As an operation moves along your link chain, it maintains a context that each link can read and modify. This allows links to pass metadata along the chain that other links use in their execution logic.

获取当前上下文对象并通过访问 op.context 进行修改。

¥Obtain the current context object and modify it by accessing op.context.

你可以通过向 queryuseQuery 钩子(或 mutationsubscription 等)提供上下文参数来设置特定操作的上下文对象的初始值。

¥You can set the context object's initial value for a particular operation by providing the context parameter to the query or useQuery hook (or mutation, subscription, etc.).

有关示例用例,请参阅 对某些请求禁用批处理

¥For an example use case, see Disable batching for certain requests.