)
TanStack Router useRouteContext Hook 全解以类型安全方式读取路由上下文Context【免费下载链接】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/routeruseRouteContext是 TanStack Router本仓库tanstack/react-router/tanstack/solid-router/tanstack/vue-router系列包中用于读取当前路由上下文Route Context的 Hook。它在父子路由之间做数据传递时极为常用——父路由把鉴权用户、主题配置等数据挂到自己的context上子路由任意深度的组件即可通过useRouteContext({ from: ... })以完全类型安全的方式取回。本文基于仓库 API 文档 useRouteContextHook.md 展开并结合核心类型定义、React 端实现与配套测试讲清它的参数、返回值、底层实现与实际用法。一、useRouteContext 是什么useRouteContext是一个返回当前路由上下文current context的 Hook其典型应用场景是在组件中访问某条路由的context对象原文档定义useRouteContextmethod is a hook that returns the current context for the current route. This hook is useful for accessing the current route context in a component.useRouteContext是一个返回当前路由上下文的 Hook便于在组件中访问该上下文。它读取的目标是路由匹配对象route match上的context字段。在 TanStack Router 中每个路由匹配都会携带由路由配置context字段与beforeLoad等函数逐层累积而来的上下文对象useRouteContext本质上是取出指定路由匹配上的context这一操作的 Hook 化封装。二、useRouteContext 的选项Options根据文档useRouteContext接受一个options对象包含两个选项opts.from选项类型string是否必填是Required含义要从中读取上下文的路由的RouteID。在类型系统层面from的取值被严格约束为当前路由树中真实存在的路由 ID。这一定义位于 router-core 核心类型 中// packages/router-core/src/useRouteContext.ts export type UseRouteContextOptions TRouter extends AnyRouter, TFrom extends string | undefined, TStrict extends boolean, TSelected, StrictOrFromTRouter, TFrom, TStrict // ^ 提供 from 选项且被约束为路由树内的 RouteID UseRouteContextBaseOptionsTRouter, TFrom, TStrict, TSelected // ^ 提供 select 选项StrictOrFrom会依据路由树对from做穷举校验——写错路由 ID 时直接产生类型错误这正是fully type-safe的体现。opts.select选项类型(context: RouteContext) TSelected是否必填否Optional含义如果提供了该函数它将以路由上下文对象为参数被调用其返回值将作为useRouteContext的返回结果。// packages/router-core/src/useRouteContext.ts export interface UseRouteContextBaseOptions TRouter extends AnyRouter, TFrom, TStrict extends boolean, TSelected, { select?: ( search: ResolveUseRouteContextTRouter, TFrom, TStrict, // ^ 参数即 from 路由的完整 context 类型 ) TSelected }select有两个实际作用一是让你只取上下文中关心的字段如context.postId二是通过返回TSelected让类型系统精确推导出 Hook 的返回类型。三、useRouteContext 的返回值文档对返回值的描述是The current context for the current route orTSelectedif aselectfunction is provided. 返回当前路由的上下文对象如果提供了select函数则返回TSelected。这一行为在核心类型中有一一对应的定义返回值类型在未 select与已 select两种情形间自动切换// packages/router-core/src/useRouteContext.ts export type ResolveUseRouteContext TRouter extends AnyRouter, TFrom, TStrict extends boolean, TStrict extends false ? AllContextTRouter[routeTree] // 非严格模式路由树全量上下文 : ExpandRouteByIdTRouter[routeTree], TFrom[types][allContext] // 严格模式from 路由的 allContext export type UseRouteContextResult TRouter extends AnyRouter, TFrom, TStrict extends boolean, TSelected, unknown extends TSelected ? ResolveUseRouteContextTRouter, TFrom, TStrict // 未提供 select返回完整 context : TSelected // 提供了 select返回 select 的返回值类型从源码结构看这里的allContext是该路由自身context与所有父路由context合并后的类型——因此在子路由中读取父路由的from时你依然能拿到完整的、含父层字段的上下文类型。四、完整示例继承原文档的示例React 端导入自tanstack/react-routerimport { useRouteContext } from tanstack/react-router function Component() { const context useRouteContext({ from: /posts/$postId }) // ^ RouteContext // OR const selected useRouteContext({ from: /posts/$postId, select: (context) context.postId, }) // ^ string // ... }两种写法的差异不带selectcontext是/posts/$postId路由的完整上下文对象字段访问受allContext类型约束带select返回select函数的计算结果示例中为string类型的postId。绑定到路由实例的useRouteContext除了裸 Hook仓库还在路由对象上内置了预绑定from的版本省去手写路由 ID。见 route.tsx// 普通路由与根路由均暴露 useRouteContextfrom 自动绑定为自身 id useRouteContext: UseRouteContextRouteRootRouteId (opts) { return useRouteContext({ ...(opts as any), from: this.id }) }即rootRoute.useRouteContext()等价于useRouteContext({ from: / })postsRoute.useRouteContext({ select: (ctx) ctx.user })等价于显式传入该路由的from。这一绑定在根路由上同样存在route.tsx#L510-L511。五、React 端实现原理useRouteContext 是 useMatch 的一层 select 封装tanstack/react-router中的实现非常薄见 packages/react-router/src/useRouteContext.tsexport function useRouteContext TRouter extends AnyRouter RegisteredRouter, const TFrom extends string | undefined undefined, TStrict extends boolean true, TSelected unknown, ( opts: UseRouteContextOptionsTRouter, TFrom, TStrict, TSelected, ): UseRouteContextResultTRouter, TFrom, TStrict, TSelected { return useMatch({ ...(opts as any), select: (match) opts.select ? opts.select(match.context) : match.context, }) as UseRouteContextResultTRouter, TFrom, TStrict, TSelected }可以确认useRouteContext完全复用useMatch读取路由匹配的响应式 Hook的订阅与更新机制只是把取值目标固定为match.context当用户提供select时在useMatch内部先取到完整context再执行select因此select函数接收的始终是完整上下文对象返回值最终类型由UseRouteContextResult推导未 select 时为from路由的allContext已 select 时为TSelected。六、测试用例佐证行为边界仓库为useRouteContext提供了多组测试可据以确认其覆盖面routeContext.test.tsx功能测试覆盖跨路由读取上下文、select过滤等场景useRouteContext.test-d.tsx类型测试验证from写错路由 ID 报错、select返回值类型推导正确pending-route-context.test.tsx 与 not-found-route-context.test.tsx从测试命名可以推断上下文的读取在路由处于 pending加载/过渡以及 not-found 等特殊状态时也有专门的行为约定涉及这些边界场景时可优先查阅对应测试。上述测试在solid-router、vue-router包中均有同名对应如 solid-router/tests/useRouteContext.test-d.tsx说明该 Hook 的 API 契约在三大框架适配层间保持一致。七、示例工程中的真实用法仓库示例 kitchen-sink-file-based 的登录路由 展示了父路由写 context、子组件读 context的典型闭环登录成功后把用户信息写入路由上下文__root等祖先路由的组件再通过useRouteContext读取当前会话状态。类似的用法也出现在 examples/react/kitchen-sink/src/main.tsx 以及各 Start 框架的 e2e 工程如 e2e/react-start/spa-mode/src/routes/posts.$postId.tsx中可作为真实项目的参考实现。八、使用要点与适用边界from必填且强类型from必须是当前路由树中存在的RouteID写错会在类型层面立即报错在路由实例上调用.useRouteContext()可以免去手写 IDselect的取舍需要完整上下文对象时不传select只取个别字段且希望返回类型精确收窄时传select上下文来源读到的context是路由匹配上的累积上下文含父路由链上的字段因此子路由组件读取祖先路由from是合法且常见的模式框架一致性核心类型定义在 packages/router-core/src/useRouteContext.tsReact 实现在 packages/react-router/src/useRouteContext.tsSolid/Vue 适配层遵循相同契约跨框架迁移时 API 无需变化。综上useRouteContext用最小的 API 面一个必填from 一个可选select实现了任意组件按路由 ID 读取、类型完整推导的上下文访问能力其实现只是对useMatch的一次context维度 select 封装因此与路由匹配机制天然同步是 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),仅供参考