TanStack Router:Router 核心 API 全解——从路由树创建、createRouter 配置到类型体系
【免费下载链接】router🤖 A client-first, server-capable, fully type-safe router and full-stack framework for the web (React and more).项目地址: https://gitcode.com/GitHub_Trending/ro/router
本文以 TanStack Router 官方 API 参考(docs/router/api/router.md)为主体,系统梳理@tanstack/react-router(及其同构的solid-router、vue-router包)中 Router 层的全部 API:17 个函数、11 个组件、18 个 Hooks、24 个核心类型与 7 个已弃用 API。读完后,你将能够独立完成路由树的搭建、createRouter的完整配置、导航/预加载/错误处理等运行时操作,并理解每个 API 在 packages/router-core 中的实现落点。
一、API 全景:Router 模块由什么组成
Router API 总览页 将整套 API 划分为五类。它们共同构成一个"客户端优先、但同样具备服务端能力"的路由层,底层由框架无关的 router-core 包 承载核心逻辑(路由匹配、位置解析、加载生命周期等),各框架包(如 packages/react-router/src/index.tsx)在此基础上提供 React 绑定。
| 分类 | 数量 | 代表 API |
|---|---|---|
| 函数 | 17 | createRouter、createRoute、getRouteApi、redirect、defer |
| 组件 | 11 | <Link>、<Outlet>、<Await>、<Navigate>、<CatchBoundary> |
| Hooks | 18 | useNavigate、useLoaderData、useParams、useRouterState |
| 类型 | 24 | RouterOptions、RouterState、RouteOptions、ToOptions |
| ⚠️ 已弃用 | 7 | Route类、Router类、RootRoute类等(见第五节) |
函数 API 清单
- 路由树构建:
createFileRoute、createLazyFileRoute、createRootRoute、createRootRouteWithContext、createRoute、createLazyRoute - 运行时创建:
createRouter - 导航与控制流:
redirect、notFound、isRedirect、isNotFound、lazyRouteComponent - 路由掩码:
createRouteMask - 搜索参数工具:
retainSearchParams、stripSearchParams - 路由 API 绑定:
getRouteApi - 异步数据:
defer
组件 API 清单
<Link>(类型化链接)、<Outlet>(嵌套出口)、<Await>(消费defer的 Promise)、<Navigate>(声明式重定向)、<MatchRoute>(按目标渲染任意路由)、<ClientOnly>(仅客户端渲染)、<ErrorComponent>、<NotFoundComponent>、<CatchBoundary>与<CatchNotFound>(边界捕获)、<DefaultGlobalNotFound>(全局 404 兜底)。
Hooks 清单
useAwaited、useBlocker、useCanGoBack、useChildMatches、useLinkProps、useLoaderData、useLoaderDeps、useLocation、useMatch、useMatchRoute、useMatches、useNavigate、useParentMatches、useParams、useRouteContext、useRouter、useRouterState、useSearch。
二、路由树构建 API:createRoute 与文件路由
2.1 createRoute 与 createRootRoute
createRoute 文档 定义了路由实例的创建方式:它接收一个RouteOptions对象并返回一个Route实例。路由实例被传入根路由的children,最终组成路由树,再交给createRouter。文档给出的标准示例:
import { createRoute } from '@tanstack/react-router' import { rootRoute } from './__root' const Route = createRoute({ getParentRoute: () => rootRoute, path: '/', loader: () => { return 'Hello World' }, component: IndexComponent, }) function IndexComponent() { const data = Route.useLoaderData() return <div>{data}</div> }注意Route.useLoaderData()这种"静态绑定"的用法:路由对象本身就是该路由的 API 入口。而在文件路由场景下,getRouteApi(见 2.3)是不持有路由对象引用时的等价手段。
createRootRoute用于创建路由树的根节点;createRootRouteWithContext则是它的"带上下文"变体——当根路由声明了上下文类型时,createRouter必须提供对应的context(见第三节context属性)。
2.2 createFileRoute / createLazyFileRoute
文件路由是 TanStack Router 的默认工作流:路由由文件系统约定生成,@tanstack/router-plugin(packages/router-plugin)在构建期产出routeTree.gen文件,其中的Route对象由生成器注入id与类型。createFileRoute 文档 中的典型用法:
import { createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/posts')({ loader: () => fetchPosts(), component: PostsComponent, })createLazyFileRoute(文档)与createLazyRoute(文档)是懒加载变体:路由的组件与加载逻辑通过lazyRouteComponent(文档)包裹,实现按路由拆分 JS chunk。
2.3 getRouteApi:类型安全的全局路由 API
getRouteApi 文档 说明,它返回useParams、useSearch、useRouteContext、useNavigate、useLoaderData、useLoaderDeps这批常用 Hook 的类型安全预绑定版本——绑定到具体路由 ID 与注册的路由类型上,无需从组件作用域内导入路由对象:
import { getRouteApi } from '@tanstack/react-router' const routeApi = getRouteApi('/posts') export function PostsPage() { const posts = routeApi.useLoaderData() // ... }在文件路由项目中,由于routeTree.gen由插件生成、id类型已知,getRouteApi('/posts')的字符串字面量参数与返回值都受到完整的类型约束——这正是"fully type-safe"主张在 API 层的直接体现。
三、createRouter 与 RouterOptions:配置路由器
3.1 createRouter 函数
createRouter 文档 定义:该函数接收一个RouterOptions对象(必填),返回一个Router实例。最小可运行示例:
import { createRouter, RouterProvider } from '@tanstack/react-router' import { routeTree } from './routeTree.gen' const router = createRouter({ routeTree, defaultPreload: 'intent', }) export default function App() { return <RouterProvider router={router} /> }在 router-core 中,路由实例的构建与状态管理集中在 Router 核心实现,入口导出见 packages/router-core/src/index.ts;React 侧的挂载则通过 RouterProvider 实现 完成——RouterProvider是createRouter返回实例与 React 渲染树之间的桥接。
3.2 RouterOptions 核心属性(节选与说明)
RouterOptions 文档 完整列举了所有配置项。以下按用途分组,给出类型、默认值与影响要点:
路由树与历史
routeTree(必填):AnyRoute,路由树本身。history(可选):RouterHistory,未提供时内部新建一个createBrowserHistory实例,历史管理的实现位于 packages/history 包。basepath(可选,默认/):整个路由器的挂载子路径,适合把路由实例挂到子路径下。origin(可选):URL 解析使用的 origin。默认取浏览器 origin,服务端或匿名 origin 下为http://localhost。文档要求传入规范化 origin(如https://example.com,不带路径与尾斜杠);若手头是完整 URL,可用new URL(url).origin归一化后再传入。caseSensitive(可选,默认false):为true时所有路由按大小写敏感匹配。trailingSlash(可选,默认'never'):'always'补尾斜杠、'never'移除、'preserve'不修改。
搜索参数解析与严格模式
stringifySearch/parseSearch(可选):自定义搜索参数序列化/反序列化函数,默认分别为defaultStringifySearch与defaultParseSearch。search.strict(可选,默认false):控制任何validateSearch未声明的"未知搜索参数"的处理。false保留,true丢弃。pathParamsAllowedCharacters(可选):Array<';' | ':' | '@' | '&' | '=' | '+' | '$' | ','>,声明哪些 URI 字符允许出现在 path 参数中而不被encodeURIComponent转义。
预加载与缓存
defaultPreload(可选,默认false):false表示不做任何预加载;'intent'在用户悬停链接或触发touchstart时预加载;'viewport'在链接进入视口时预加载;'render'在链接渲染进 DOM 时立即预加载。defaultPreloadDelay(可选,默认50):intent 悬停/视口预加载前的延迟毫秒数;touch intent 立即预加载。defaultStaleTime(默认0)、defaultPreloadStaleTime(默认30_000ms)、defaultPreloadGcTime与defaultGcTime(均默认 5 分钟):控制 loader 数据新鲜度与预加载/缓存条目的回收时机。defaultStaleReloadMode(可选,默认'background'):过期 loader 数据的重新验证方式。'background'保持 stale-while-revalidate 行为;'blocking'则等待过期的 loader 重载完成后才让导航 resolve。
组件与等待态兜底
defaultComponent(默认Outlet):路由未提供component时的默认组件。defaultErrorComponent(默认ErrorComponent)、defaultNotFoundComponent(默认NotFound):错误与 404 的默认渲染。defaultPendingComponent、defaultPendingMs(默认1000)、defaultPendingMinMs(默认500):pending 组件及其显示/最短展示时间。defaultOnCatch(可选):(error, errorInfo) => void,Router 内部 ErrorBoundary 捕获错误的默认处理器。disableGlobalCatchBoundary(可选,默认false):true时禁用包裹所有路由匹配的兜底捕获边界,让未处理错误冒泡到浏览器顶层错误处理器——文档指出这主要用于测试工具、错误上报服务与调试场景。
安全:protocolAllowlist
protocolAllowlist(可选,默认DEFAULT_PROTOCOL_ALLOWLIST):允许出现在链接、重定向与导航中的 URL 协议数组,默认覆盖 Web 导航(http:、https:)与常见浏览器安全动作(mailto:、tel:)。不在白名单内的绝对 URL 会被拒绝,用于防御 XSS 类风险。文档强调该检查横跨<Link to="...">、navigate({ to/href })、redirect({ to/href })三类导航 API;条目必须匹配URL.protocol格式(小写带尾冒号),配置成'blob'(不带:)将无法放行blob:链接。
import { createRouter, DEFAULT_PROTOCOL_ALLOWLIST, } from '@tanstack/react-router' // 使用自定义白名单(替换默认值) const router = createRouter({ routeTree, protocolAllowlist: ['https:', 'mailto:'], }) // 或在默认白名单基础上扩展 const router = createRouter({ routeTree, protocolAllowlist: [...DEFAULT_PROTOCOL_ALLOWLIST, 'ftp:'], })导航行为
defaultViewTransition(可选):true时导航通过document.startViewTransition()执行;传ViewTransitionOptions对象时可附带types数组走startViewTransition({ update, types }),浏览器不支持 types 时回退为普通 view transition;浏览器完全不支持该 API 时此选项被忽略。defaultHashScrollIntoView(可选,默认true):位置写入历史后,是否将 id 与 hash 匹配的元素滚动到视口内;传对象则作为scrollIntoView的选项。rewrite(可选):LocationRewrite,在浏览器 URL 与路由器内部 URL 之间做双向转换,详见 3.3。context(可选;若根路由用createRootRouteWithContext()创建则必填):注入给整棵路由树的根上下文,避免逐路由提供。dehydrate/hydrate(可选):SSR 脱水/注水时由用户扩展的序列化钩子,返回值会并入路由器的脱水状态。
404 与 URL 整形
notFoundMode(可选,默认'fuzzy'):'root' | 'fuzzy',控制找不到匹配路由时的行为。notFoundRoute(已弃用):整棵路由树的默认 404 路由,可被各分支根路由的选项覆盖。defaultStructuralSharing(可选,默认false):为细粒度选择器默认启用结构化共享。defaultRemountDeps(可选):(opts) => any,依据routeId、search、params、loaderDeps计算组件重挂载依赖,返回值需 JSON 可序列化;返回值得变化时组件重挂载,默认导航后保持激活的组件不重挂载。例如remountDeps: ({ params }) => params可让所有路由组件在params变化时重挂载。
3.3 URL Rewrites:rewrite 配置详解
rewrite的类型形状(引自 RouterOptions 文档):
type LocationRewrite = { input?: LocationRewriteFunction output?: LocationRewriteFunction } type LocationRewriteFunction = (opts: { url: URL }) => undefined | string | URLinput:路由器解释 URL 之前的转换(浏览器 → 路由器);output:写入浏览器历史之前的转换(路由器 → 浏览器)。
文档中的 i18n 前缀示例:
import { createRouter } from '@tanstack/react-router' const router = createRouter({ routeTree, rewrite: { input: ({ url }) => { // Strip locale prefix: /en/about → /about if (url.pathname.startsWith('/en')) { url.pathname = url.pathname.replace(/^\/en/, '') || '/' } return url }, output: ({ url }) => { // Add locale prefix: /about → /en/about url.pathname = `/en${url.pathname === '/' ? '' : url.pathname}` return url }, }, })文档特别说明:当basepath与rewrite同时配置时二者自动组合——input 阶段 basepath 剥离最先执行,output 阶段 basepath 回填最后执行。这一机制在 router-core 中的独立实现见 rewrite 模块。
3.4 Wrap / InnerWrap:渲染包装层
Wrap(可选):包裹整个路由器的组件,只应使用不产生 DOM 的 Provider 类组件,否则会引发 hydration 错误:
const router = createRouter({ Wrap: ({ children }) => { return <MyContext.Provider value={myContext}>{children}</MyContext> }, })InnerWrap(可选):包裹路由器内部内容的组件,与Wrap的关键区别是它可以访问路由器上下文与 Hook:
const router = createRouter({ InnerWrap: ({ children }) => { const routerState = useRouterState() return ( <MyContext.Provider value={myContext}> {children} </MyContext> ) }, })同样地,两者都只应承载 Provider 一类不渲染 DOM 的组件。
四、Router 实例方法:运行时能力
Router 类型文档 描述了实例的全部成员。核心提醒:router.state永远是最新的,但不是响应式的——在组件里读router.state不会触发重渲染,响应式读取必须使用useRouterState。
| 成员 | 签名要点 | 说明 |
|---|---|---|
.update | (newOptions: RouterOptions) => void | 用新选项更新路由实例 |
state | RouterState | 当前状态(非响应式) |
.subscribe | (eventType, fn) => () => void | 订阅 RouterEvent,返回退订函数 |
.matchRoutes | (pathname, search?, opts?) => RouteMatch[] | 匹配路径与搜索参数;throwOnError: true时匹配错误会抛出 |
.buildLocation | (opts: BuildNextOptions) => ParsedLocation | 构建待导航的位置对象 |
.commitLocation | (location & { replace?, resetScroll?, hashScrollIntoView?, ignoreBlocker? }) => Promise<void> | 将位置提交到浏览器历史 |
.navigate | (options: NavigateOptions) => Promise<void> | 导航到新位置 |
.invalidate | (opts?: { filter?, sync?, forcePending? }) => Promise<void> | 失效选中的路由匹配代际并重跑加载生命周期 |
.clearCache | (opts?: { filter? }) => void | 清除缓存的路由匹配与活动预加载 |
.load | (opts?: { sync? }) => Promise<void> | 加载当前所有匹配,SSR 常用 |
.preloadRoute | (opts: NavigateOptions) => Promise<RouteMatch[] \| undefined> | 预加载目标匹配 |
.loadRouteChunk | (route: AnyRoute) => Promise<void> | 加载路由的 JS chunk |
.matchRoute | (dest: ToOptions, matchOpts?) => RouteMatch['params'] \| false | 匹配并返回参数 |
.dehydrate/.hydrate | () => DehydratedRouter/(dehydrated) => void | SSR 状态序列化/反序列化 |
几个值得展开的要点:
buildLocation的 updater 语义:params、search、hash、state均可传true(沿用当前值)或传 updater 函数(以当前值为入参、返回新值);mask字段内嵌完整BuildNextOptions并额外支持unmaskOnReload。commitLocation默认行为:replace默认false(用history.push);resetScroll默认true(提交后滚动复位到 0,0);hashScrollIntoView默认true;ignoreBlocker默认false。.invalidate的语义边界:不传filter时失效所有已提交、缓存与在途的匹配代际;传filter时它作用于同一集合,选中一代即失效同一 match ID 的所有代际。失效会重跑beforeLoad,可复用的 loader 数据被标记为过期后走正常加载协议,而 match ID 不变时路由级context保持可复用。sync: true使返回的 Promise 在过期加载完成后才 resolve;forcePending: true让已有成功数据的路由也进入正常 pending 协议。.load与staleTime:文档明确警告router.load()尊重route.staleTime——新鲜的匹配保持新鲜,过期匹配会被重新验证;需要无视新鲜度强制重载时应改用router.invalidate()。其最常见用途是 SSR 场景:在流式渲染客户端之前确保当前路由的关键数据全部就绪。.preloadRoute的推测性:活动预加载是推测性的,不会成为当前呈现的匹配;成功的 loader 数据可进入内存缓存,新鲜度遵循preloadStaleTime,闲置且超过preloadGcTime后可在后续缓存对账中被回收。每个预加载与导航各自执行beforeLoad链:后续 lane 可复用已结算的 loader 数据或并入进行中的 loader 工作,但从不复用beforeLoad上下文或已结算的 redirect/error/not-found 结果。该方法在服务端路由实例上同样可用,且不影响请求当前的位置与呈现匹配。
五、导航、控制流与搜索参数工具函数
5.1 redirect 与 notFound
redirect在 loader/beforeLoad中抛出以触发类型安全重定向;isRedirect是其守卫函数。notFound抛出 404 语义的错误;isNotFound对应判断。这四个函数在 router-core 中分别对应 redirect 实现 与 not-found 实现。
5.2 retainSearchParams 与 stripSearchParams
retainSearchParams与stripSearchParams是searchupdater 的辅助:前者只替换指定键、保留其余搜索参数,后者剔除指定键、保留其余。它们让"改一个参数而不打乱 URL 里其它参数"成为一行代码的事。
5.3 defer 与 :流式渲染
defer在 loader 中返回一组延迟 Promise;配套的<Await>组件与useAwaitedHook 负责消费它们,实现"首屏关键数据先渲染、非关键数据流式补全"。defer的运行时支持位于 packages/router-core/src/defer.ts,服务端流式渲染的入口在 router-core 的 ssr 目录。
六、路由掩码:createRouteMask
createRouteMask 文档 定义:该函数创建一个RouteMask配置对象,供RouterOptions.routeMasks使用。"路由掩码"指以与配置匹配不同的路径来显示某条路由——典型场景是弹窗:用户看到的是/photos/$photoId/modal,但把链接分享出去或刷新后,落地的是弹窗内容本身而非弹窗上下文。
import { createRouteMask, createRouter } from '@tanstack/react-router' const photoModalToPhotoMask = createRouteMask({ routeTree, from: '/photos/$photoId/modal', to: '/photos/$photoId', params: true, }) const router = createRouter({ routeTree, routeMasks: [photoModalToPhotoMask], })与掩码配合的两个路由器级选项:routeMasks(掩码数组)与unmaskOnReload(默认false,true时页面刷新默认解除掩码;可在单个 mask 或单次导航的NavigateOptions.mask.unmaskOnReload上覆盖)。
七、类型体系
总览页 列出的 24 个类型是整套 API 的类型契约,按职责可分为四组:
- 路由器契约:
Router、RouterOptions、RouterState、RouterEvents、Register(模块级类型注册入口)。 - 路由与匹配:
Route、RouteOptions、RouteApi、RouteMatch、RouteMask、MatchRouteOptions、UseMatchRouteOptions、AsyncRouteComponent。 - 位置与历史:
ParsedLocation、HistoryState、ParsedHistoryState。 - 导航与错误:
ToOptions、ToMaskOptions、NavigateOptions、LinkOptions/LinkOptions/LinkProps/ActiveLinkOptions、ViewTransitionOptions、Redirect、NotFoundError。
这些类型在源码层面的公共入口是 router-core 的 typePrimitives 模块 与总 index 导出;框架包(如 packages/react-router/src/index.tsx)会将其连同框架绑定一起再导出。
八、已弃用 API 与迁移方向
总览页 标注了 7 个 ⚠️ Deprecated 条目:FileRoute类、Route类、Router类、RouteApi类、RootRoute类、NotFoundRoute类 与rootRouteWithContext函数(文档)。
从文档结构可以确认,当前版本的 API 设计已全部转向函数式:类被createFileRoute/createRoute/createRootRoute/createRootRouteWithContext等工厂函数取代,routeRouteWithContext由createRootRouteWithContext取代。新代码应直接采用函数式 API,避免触碰上述类。
九、API 与实现的对应关系
| API | 文档 | 源码落点(router-core 为框架无关核心) |
|---|---|---|
createRouter/ Router 实例 | createRouterFunction.md | packages/router-core/src/router.ts、packages/router-core/src/root.ts |
createRoute/ 路由实例 | createRouteFunction.md | packages/router-core/src/route.ts |
| 文件路由(React 绑定) | createFileRouteFunction.md | packages/react-router/src/fileRoute.ts |
redirect/notFound | redirectFunction.md | packages/router-core/src/redirect.ts、packages/router-core/src/not-found.ts |
rewrite | RouterOptionsType.md | packages/router-core/src/rewrite.ts |
defer | deferFunction.md | packages/router-core/src/defer.ts |
<Link> | linkComponent.md | packages/router-core/src/link.ts、packages/react-router/src/link.tsx |
useNavigate/useRouterState | useNavigateHook.md | packages/router-core/src/useNavigate.ts、packages/react-router/src/useRouterState.tsx |
从源码结构看,router-core承担了匹配(matches 模块)、位置解析(location 模块)、搜索参数中间件(searchMiddleware 模块)、结构化共享(structuralSharing 模块)等横切能力,各框架包只做渲染与响应式绑定——这解释了为何同一套 API 参考可以覆盖 React、Solid、Vue 三种前端。
十、小结
- 路由树由
createRootRoute/createRoute(或文件路由下的createFileRoute/createLazyFileRoute)构建,最终交给createRouter({ routeTree, ... })装配成可运行的路由器,RouterProvider负责将其挂载进应用; RouterOptions是全部行为的配置面:预加载策略(defaultPreload/defaultPreloadDelay)、缓存新鲜度(staleTime系列)、404 策略(notFoundMode)、安全边界(protocolAllowlist)、URL 整形(basepath/rewrite/trailingSlash)与 SSR 序列化(dehydrate/hydrate)都从这里配置;- 运行时导航能力集中在 Router 实例方法:
navigate/buildLocation/commitLocation处理位置流转,invalidate/clearCache/preloadRoute/load处理数据与缓存生命周期,subscribe暴露完整事件流; getRouteApi提供了不依赖组件作用域的类型安全 Hook 绑定,与retainSearchParams/stripSearchParams、defer/<Await>、createRouteMask一起,覆盖了搜索参数、流式数据与弹窗路由三类高频实战场景;- 类式 API 已全部弃用,编写新代码时直接使用第八节之前的函数式 API 即可。
【免费下载链接】router🤖 A client-first, server-capable, fully type-safe router and full-stack framework for the web (React and more).项目地址: https://gitcode.com/GitHub_Trending/ro/router
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考