路由
Router 是 Provider 作用域状态,不是全局单例。一个 RouterProvider 持有一条 RouterHistory,并通过 Context 把当前路由上下文和导航能力传给子树。
想先看完整运行例子,可以从 路由工作台 开始。
路由运行时可以分成三层:
| 层 | 生命周期 | 内容 |
|---|---|---|
RouterHistory | 跟随 RouterProvider | history 栈、当前指针、最大历史长度 |
RouteContext | 当前 history entry | 当前 path、动态 params、可选 RouteState |
Route | 路由表定义 | path pattern、组件、子路由 |
Navigate 写的是 RouterHistory。Outlet 读当前 RouteContext,按 routes! 声明顺序找到第一个匹配的 Route,并把剩余 path 交给嵌套 Outlet 继续消费。
RouterProvider(history_length: n) 可以限制 history 栈长度。默认是 10;传入 0 会按 1 处理,也就是只保留当前最新 entry。
Navigate
Section titled “Navigate”use_navigate() 返回 Navigate 句柄,常用方法如下:
| 方法 | 行为 |
|---|---|
push(path) | 新增一条 history entry,并清空 route state |
push_with_state(path, state) | 新增 history entry,并携带一次性 state |
replace(path) | 替换当前 history entry,并清空 route state |
replace_with_state(path, state) | 替换当前 history entry,并携带一次性 state |
go(delta) | 按偏移移动 history 指针,负数后退、正数前进 |
back() / forward() | go(-1) / go(1) 的语义化快捷方式 |
Navigate 写入的是当前 RouterProvider 里的 RouterHistory,不是全局路由单例。同一个应用可以嵌多个 RouterProvider,它们各自维护自己的 history。
父路由组件可以渲染固定外壳,然后在内部放 Outlet。路径 /projects/boreal 会先进入 AppShell,再由子 Outlet 命中 /projects/:slug。
静态路由使用前缀匹配并要求段边界;动态参数只匹配单段,不会跨 /。同前缀路由需要把更具体的动态路由放在前面,例如 /projects/:slug 要先于 /projects。
参数和 state
Section titled “参数和 state”动态参数从 path 来:
如果页面需要当前命中的路由定义本身,可以用 use_route():
多数业务页面只需要 use_params()。use_route() 更适合调试、面包屑、路由可视化或封装自己的路由辅助组件。
RouteState 从导航行为来:
try_use_route_state::<T>() 找不到 Router context、没有 state 或类型不匹配时返回 None。use_route_state::<T>() 是断言型 API,会在缺失或类型不匹配时 panic。
普通 push(path) 和 replace(path) 会清空当前 route state;只有 push_with_state 和 replace_with_state 会显式携带 state。这能避免从详情页跳到普通页时把旧 state 泄漏到新页面。
为什么不用 Atom
Section titled “为什么不用 Atom”Atom 是进程级状态;Router 是 Provider 作用域状态。把默认 Router 存到 Atom 会让多个 RouterProvider 互相污染,也会让测试、嵌入式子应用和局部导航变难。
需要外部可控路由时,优先设计显式 controlled Router API,例如由调用方传入当前 path 和变更回调。只有真正跨 Provider 共享的业务状态,才应该进入 Atom。