拓冰建站拓冰建站
首页 / 资讯中心 / 正文

TanStack Router 路由事件订阅指南:用 router.subscribe 精准感知导航生命周期

TanStack Router 路由事件订阅指南用 router.subscribe 精准感知导航生命周期【免费下载链接】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 通过router.subscribe对外暴露完整的路由生命周期事件让开发者可以以命令式方式监听导航开始、路由加载、组件挂载、导航完成等关键节点。这篇指南将带你掌握router.subscribe的完整用法事件列表、触发顺序、事件载荷payload字段语义以及埋点统计、外部状态清理、DOM 操作等真实场景的落地写法同时结合本仓库 router-core 的源码实现说明这些事件在内部到底是如何被计算和发射的。基本用法订阅与取消订阅router.subscribe接收两个参数事件名与监听器函数并返回一个unsubscribe函数用于移除监听const unsubscribe router.subscribe(onResolved, (event) { console.info(Navigation finished:, event.toLocation.href) }) // 稍后清理监听器 unsubscribe()从源码看subscribe的实现非常轻量packages/router-core/src/router.ts#L1407-L1418它将{ eventType, fn }包装成一个 listener 放入内部的subscribers集合Set返回的闭包负责从集合中删除该 listener。这意味着同一事件可以注册多个监听器它们都会被依次调用返回的unsubscribe是幂等且安全的——即使重复调用也不会报错监听器内部抛出的异常会被emit捕获并console.errorrouter.ts#L1420-L1430不会中断其他监听器也不会影响路由本身的导航流程。何时该用 router.subscriberouter.subscribe最适合那些需要观察导航、但不需要驱动渲染的命令式集成场景埋点与页面访问pageview统计重置外部缓存或 mutation 状态记录导航耗时与过渡过程在路由渲染完成后执行依赖 DOM 的逻辑如聚焦标题、滚动定位如果你需要的是响应式的 UI 更新则应当优先使用框架 Hooks如useRouterState、useSearch、useParams而不是手动订阅。订阅是命令式的一次性回调不会触发组件重渲染Hooks 则会与渲染周期绑定自动在状态变化时重渲染。可用事件一览TanStack Router 会发射以下生命周期事件事件名触发时机onBeforeNavigate一次导航即将开始之前onBeforeLoad路由加载开始之前onLoad下一个 location 已提交、路由匹配matches已加载完成之后onBeforeRouteMount加载完成后、路由组件即将挂载之前onResolved导航完全解析resolve之后onRendered路由渲染完成之后此外事件类型中还存在一个onInjectedHtml事件仅在服务端 SSR 场景由ssr-server触发用于注入 HTML 流时回调完整的事件载荷类型定义见 RouterEventsType 类型文档。每个事件的 payload 都以事件名作为type字段可用于在同一个监听函数内进行可辨识联合discriminated union判断router.subscribe(onResolved, (event) { if (event.type onResolved) { // 类型被收窄为 onResolved 的载荷 } })典型事件流对于一次正常导航事件通常按以下顺序流动onBeforeNavigateonBeforeLoadonLoadonBeforeRouteMountonResolvedonRendered在客户端实现中packages/router-core/src/load-client.ts#L1952-L1958onBeforeNavigate与onBeforeLoad在路由匹配与资源获取之前同步发射而在匹配加载完成、location 提交之后load-client.ts#L1877-L1909依次发射onLoad、onBeforeRouteMount并在resolvedLocation更新、router 状态回到idle后发射onResolved与onRendered。服务端SSR路径同样会发射onBeforeNavigate与onBeforeLoad见 packages/router-core/src/load-server.ts#L891-L894因此基于这两个事件编写的导航开始类逻辑在服务端渲染时也能生效。需要注意onBeforeNavigate与onBeforeLoad之间存在一个 preflight 中断检查load-client.ts#L1955-L1958——如果导航被更快的后续导航取代abortonBeforeLoad可能不会发射。因此若必须在加载开始时做副作用建议以onBeforeNavigate为准或同时兼容两个事件。你通常不需要监听所有事件。经验法则用onBeforeNavigate或onBeforeLoad观察导航开始用onResolved做埋点统计与导航完成后的清理用onRendered做依赖 DOM 的工作事件载荷location 变化元数据导航类事件都会携带描述从哪到哪、发生了什么变化的元数据const unsubscribe router.subscribe(onBeforeNavigate, (event) { console.info({ from: event.fromLocation?.href, to: event.toLocation.href, pathChanged: event.pathChanged, hrefChanged: event.hrefChanged, hashChanged: event.hashChanged, }) })几个关键细节fromLocation在首次加载时可能是undefined因为不存在上一个已解析的 locationpathChanged表示pathname 是否变化hrefChanged覆盖pathname、search、hash 的任意变化hashChanged用于区分仅 hash 变化的导航例如锚点跳转。这些布尔标志的语义直接来自源码中的getLocationChangeInfopackages/router-core/src/router.ts#L926-L937export function getLocationChangeInfo(location, resolvedLocation) { return { fromLocation: resolvedLocation, toLocation: location, pathChanged: resolvedLocation?.pathname ! location.pathname, hrefChanged: resolvedLocation?.href ! location.href, hashChanged: resolvedLocation?.hash ! location.hash, } }即pathChanged是比较新旧pathnamehrefChanged是比较完整hrefhashChanged是比较hash。fromLocation/toLocation的类型为ParsedLocation解析后的强类型 location包含pathname、search、hash、href、state等字段详见 ParsedLocation 类型文档因此你可以在监听器里安全地读取这些结构化字段而不必手动解析 URL 字符串。常见模式跟踪页面访问pageviewonResolved是埋点的首选事件因为它在导航完全结束后才触发此时toLocation即最终落地的页面const unsubscribe router.subscribe(onResolved, ({ toLocation }) { analytics.track(page_view, { path: toLocation.pathname, href: toLocation.href, }) })清除外部 mutation 状态如果你使用的 mutation 库没有按 key 隔离的 mutation 状态例如一个全局的 mutation cache可以在导航后清理——但只应在路径确实变化时清理避免同路径下的 search/hash 变化误伤const unsubscribe router.subscribe(onResolved, ({ pathChanged }) { if (pathChanged) { mutationCache.clear() } })执行依赖 DOM 的逻辑当副作用依赖新路由内容已经在 DOM 中时使用onRenderedconst unsubscribe router.subscribe(onRendered, ({ toLocation }) { focusPageHeading(toLocation.pathname) })onRendered的发射条件带有rendered判断load-client.ts#L1908-L1910确保只有真正完成渲染的提交才会触发因此比onResolved更适合 DOM 操作。事实上TanStack Router 内置的滚动恢复功能正是依赖onBeforeLoad记录滚动位置、onRendered恢复滚动位置见 packages/router-core/src/scroll-restoration.ts#L216 与 scroll-restoration.ts#L239可以作为官方同款的订阅范例参考。在组件中正确取消订阅如果你在组件或框架的 effect 中订阅一定要把返回的unsubscribe函数作为清理函数返回确保组件卸载时监听器被移除避免内存泄漏与重复触发import { useEffect } from react import { useRouter } from tanstack/react-router function PageViewTracker() { const router useRouter() useEffect(() { return router.subscribe(onResolved, ({ toLocation }) { analytics.track(page_view, { path: toLocation.pathname }) }) }, [router]) return null }由于subscribe返回的正是清理函数本身直接return router.subscribe(...)即可满足 React 对 effect 清理函数的要求。与路由 Hooks 的分工router.subscribe解决的是过程观察问题而useRouterState、useSearch、useParams等 Hooks 解决的是状态渲染问题需要渲染当前 location、search、params → 用 HooksuseRouterStateHook、useSearchHook、useParamsHook需要在导航过程中执行一次性副作用→ 用router.subscribe需要读取当前 router 状态快照如resolvedLocation、status→ 参考 RouterState 类型文档 与 Router 类型文档。小结router.subscribe是 TanStack Router 面向命令式集成场景的官方事件通道覆盖了从导航开始到渲染完成的完整生命周期。通过本文介绍的六个事件、标准事件流、payload 字段语义与三类常见模式你可以把埋点统计、缓存清理、DOM 操作等副作用干净地挂接到路由上结合 router-core 源码 中subscribe/emit/getLocationChangeInfo的实现还能准确预判不同导航首次加载、路径变化、hash-only 变化、被取代的导航下的事件行为。如果你的侧重点是在导航过程中同步修改数据例如加载完成后的数据变更流程可以进一步阅读 数据变更指南它与本文的路由事件机制共同构成 TanStack Router 导航闭环的两大观测入口。【免费下载链接】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),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门