首页
/ Next.js Pages Router 中取消 tRPC 请求:abortOnUnmount 的全局与按请求配置指南

Next.js Pages Router 中取消 tRPC 请求:abortOnUnmount 的全局与按请求配置指南

2026-09-08 09:06:46作者:仰钰奇

组件卸载时,浏览器中已经发出的 HTTP 请求并不会自动停止,tRPC 默认也不会替你取消这些请求。本文以 Next.js Pages Router 集成(@trpc/next)为背景,讲解如何通过 abortOnUnmount 配置,让查询在相关组件卸载时被真正中断,涵盖全局开启、按请求覆盖、配置优先级以及底层信号传递原理,帮助你在"卸载即丢弃结果"与"卸载即释放连接"两种策略间做出正确选择。

本文对应的官方文档为 aborting-procedures.md,其中关于"取消请求"的机制在 react-query 版本文档 中有互补说明,两篇配合阅读可获得完整视图。

一、为什么需要主动取消:默认行为与取舍

在 Next.js Pages Router 应用中,一个典型的 useQuery 调用会在页面渲染时发起请求。当用户导航离开当前页面、或条件渲染使某个查询组件卸载时,如果请求尚未完成,会出现两种情况:

  • 默认(不取消):底层 HTTP 请求继续在浏览器中执行直到返回,React Query 只是不再把结果交给已卸载的组件。这意味着网络带宽与连接资源仍被占用,尤其对于耗时较长的查询、弱网环境或大数据量响应,这是一种浪费。
  • 启用取消:请求在组件卸载时被中断,浏览器真正终止该 fetch,释放连接。

tRPC 给出的默认策略是不自动取消("By default, tRPC does not cancel requests on unmount"),把选择权交给开发者。如果你希望采用"卸载即取消"的策略,需要显式开启 abortOnUnmount

这一取舍也解释了为什么该选项被设计为可配置而非默认开启:取消请求会让"组件短暂卸载后立刻重新挂载"的场景无法复用仍在途中的数据,而保留请求则可能让页面快速恢复已有结果。

二、全局启用:在 config() 中配置 abortOnUnmount

Pages Router 集成通过 createTRPCNext 创建客户端。全局开启取消行为只需要在 config() 回调返回的配置对象中加入 abortOnUnmount: true 即可,官方示例位于 aborting-procedures.md

import { httpBatchLink } from '@trpc/client';
import { createTRPCNext } from '@trpc/next';
import type { AppRouter } from './server/routers/_app';

export const trpc = createTRPCNext<AppRouter>({
  config() {
    return {
      links: [
        httpBatchLink({
          url: '/api/trpc',
        }),
      ],
      abortOnUnmount: true,
    };
  },
});

关键点说明:

  • config()createTRPCNext 的必填回调,返回的配置同时用于初始化 tRPC 客户端与 React Query 的 QueryClient;
  • links 中可选用 httpBatchLink(请求合并)或 httpLink(单请求),两者在底层都是 fetch,取消语义一致;
  • abortOnUnmount: truelinks 平级,位于返回对象顶层。

源码侧验证:该配置如何流入 Provider

abortOnUnmount 并不是 links 的组成部分,而是一等配置项。在 withTRPC.tsx 中可以看到 Pages Router 的 HOC 配置类型把它显式声明出来:

export type WithTRPCConfig<TRouter extends AnyRouter> =
  CreateTRPCClientOptions<TRouter> &
    CreateTRPCReactQueryClientConfig & {
      abortOnUnmount?: boolean;
    };

随后 withTRPC 在创建 Provider 时读取该值并将其传入 context:

  • withTRPC.tsx 第 113-123 行const config = getClientConfig({}) 之后取出 abortOnUnmount: config.abortOnUnmount 存入 prepass props;
  • withTRPC.tsx 第 139-146 行:将 abortOnUnmount={(prepassProps as any).abortOnUnmount ?? false} 传给 <trpc.Provider>?? false 确保未配置时严格回退到默认关闭。

也就是说,全局配置最终通过 React Context 下发到每个 hook,服务端预取(SSR)阶段该值同样会被携带,但卸载取消这一行为只对浏览器端有意义。

三、按请求覆盖:在 useQuery 的选项中单独指定

取消行为并不强制全局统一。你也可以在单个查询上覆盖全局配置,实现"大多数请求保留、个别昂贵请求取消"的精细控制。官方示例(见 aborting-procedures.md)演示了在获取某篇文章详情的页面中按请求开启取消:

import { trpc } from '../../utils/trpc';
import { useRouter } from 'next/router';

function PostViewPage() {
  const id = useRouter().query.id as string;
  const postQuery = trpc.post.byId.useQuery({ id }, { trpc: { abortOnUnmount: true } });

  return null;
}

要点说明:

  • 覆盖开关放在 useQuery 第二个参数(React Query options)的 trpc 命名空间下,即 { trpc: { abortOnUnmount: true } }
  • 示例中 id 取自 useRouter().query.id,这是 Pages Router 动态路由([id])读取路径参数的常规方式;
  • 当用户在此页面数据返回前跳转到其他路由导致组件卸载时,本次 byId 请求将被取消;而项目里其他未显式声明的查询仍遵循全局配置。

配置优先级:按请求 > 全局 config > Provider 默认值

单次请求、全局 config 与 Provider 三层都可能出现该选项,实际生效值遵循一个清晰的降级链。以 createHooksInternal.tsx 中查询 hook 的解析逻辑为例:

const shouldAbortOnUnmount =
  opts?.trpc?.abortOnUnmount ?? config?.abortOnUnmount ?? abortOnUnmount;

即:useQuery 选项中的 trpc.abortOnUnmount 优先于全局 config() 中的值,全局 config() 又优先于 Provider 接收的默认值。Provider 一侧的兜底默认在 createHooksInternal.tsx 第 101 行 通过 const { abortOnUnmount = false, ... } = props 实现,与 withTRPC 传入的 ?? false 保持一致。这一逻辑在代码库中应用于查询、无限查询等多条 hook 路径(如 createHooksInternal.tsx 第 255-257、288-290 行),保证各入口解析策略一致。

四、底层原理:取消是如何传导到 HTTP 层的

在 React Query 的模型里,每个查询的 queryFn 都会收到一个 AbortSignalqueryFunctionContext.signal)。tRPC 要做的就是把这个 signal 透传给自己的请求链路。源码中,当 shouldAbortOnUnmounttrue 时,hook 会把该 signal 注入 tRPC options;反之则显式置为 null,避免意外取消。见 createHooksInternal.tsx 第 209-218 行

queryFn: isInputSkipToken
  ? input
  : async (queryFunctionContext) => {
      const actualOpts = {
        ...ssrOpts,
        trpc: {
          ...ssrOpts?.trpc,
          ...(shouldAbortOnUnmount
            ? { signal: queryFunctionContext.signal }
            : { signal: null }),
        },
      };
      // 后续用 actualOpts 执行实际过程调用……
    },

当组件卸载导致该查询不再有活跃的观察者时,React Query 会触发取消流程并 abort 这个 signal;由于 tRPC 客户端(httpLink / httpBatchLink 底层的 fetch)收到了该 signal,浏览器便会真正中断在途的 HTTP 传输,而不是等待响应返回后再丢弃。

仓库测试如何验证该行为

abortOnUnmount.test.tsx 用两个对照用例验证了配置的真实效果。测试路由中的 greeting 过程故意延迟 2000ms 返回:

  • abortOnUnmount(开启):用 createTRPCReact({ abortOnUnmount: true }) 创建的 proxy 发起查询后,切换 state 使旧查询组件卸载。断言 isFetching: 1——说明第一个请求已被中断,只剩新挂载的查询仍在拉取;
  • abortOnUnmount false(默认):相同操作后断言 isFetching: 2——两个请求都在继续执行,卸载并未中止旧请求。

如果你要为自己项目实现类似验证,可参考该测试的搭建模式:用 createTRPCReact 创建 proxy、经 httpBatchLink 指向测试服务端,并通过 useIsFetching 观察在途请求数量。

五、使用边界与注意事项

结合文档与源码,使用 abortOnUnmount 时有几点需要明确:

  1. 它针对的是卸载时的查询取消。文档措辞是组件卸载(unmount)时取消请求;若你只是想手动取消某个在途请求,应走 React Query 的 cancelQueries 或 tRPC 客户端自身的取消能力,二者场景不同。
  2. 取消作用于"拉取中"的请求。对已经完成并缓存的查询,卸载不会删除缓存数据,重新进入页面时仍能命中缓存,这正是 React Query 数据复用价值的体现。
  3. SSR 场景无需担心:服务端预取阶段不涉及"组件卸载取消"的语义,该配置在浏览器端才真正生效;withTRPC 的兜底逻辑保证了未配置时行为完全等同默认。
  4. 与请求合并(batching)的交互:在 httpBatchLink 下多个查询共享一个 HTTP 请求。取消语义由底层 fetch 的 signal 承载,具体到"单个批内查询被取消是否中断整个批量请求",取决于 signal 与批量调度的实现细节,建议在实际批量场景中按需验证。
  5. 按请求覆盖是渐进式启用取消的最佳方式:先对耗时最长、数据最"一次性"的查询开启,观察网络面板确认收益,再决定是否全局推广,而不是一上来就全局开启。

六、延伸阅读

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
900
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
927
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.89 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
602
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
396
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
526