跳转到内容

路由

Router 是 Provider 作用域状态,不是全局单例。一个 RouterProvider 持有一条 RouterHistory,并通过 Context 把当前路由上下文和导航能力传给子树。

let mut navigate = hooks.use_navigate();
navigate.push("/projects/boreal");

想先看完整运行例子,可以从 路由工作台 开始。

RouterProvider 保存 history;Outlet 根据 RouteContext 匹配 Route,并把命中的组件渲染出来。

路由运行时可以分成三层:

生命周期内容
RouterHistory跟随 RouterProviderhistory 栈、当前指针、最大历史长度
RouteContext当前 history entry当前 path、动态 params、可选 RouteState
Route路由表定义path pattern、组件、子路由

Navigate 写的是 RouterHistoryOutlet 读当前 RouteContext,按 routes! 声明顺序找到第一个匹配的 Route,并把剩余 path 交给嵌套 Outlet 继续消费。

RouterProvider(history_length: n) 可以限制 history 栈长度。默认是 10;传入 0 会按 1 处理,也就是只保留当前最新 entry。

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。

let routes = routes! {
    "/" => AppShell {
        "/" => OverviewPage,
        "/projects/:slug" => ProjectDetailPage,
        "/projects" => ProjectsPage,
    },
};

父路由组件可以渲染固定外壳,然后在内部放 Outlet。路径 /projects/boreal 会先进入 AppShell,再由子 Outlet 命中 /projects/:slug

静态路由使用前缀匹配并要求段边界;动态参数只匹配单段,不会跨 /。同前缀路由需要把更具体的动态路由放在前面,例如 /projects/:slug 要先于 /projects

动态参数从 path 来:

let params = hooks.use_params();
let slug = params.get("slug");

如果页面需要当前命中的路由定义本身,可以用 use_route()

let route = hooks.use_route();
let pattern = route.path.as_str();

多数业务页面只需要 use_params()use_route() 更适合调试、面包屑、路由可视化或封装自己的路由辅助组件。

RouteState 从导航行为来:

navigate.push_with_state(
    "/projects/boreal",
    RouteNotice { message },
);

let notice = hooks.try_use_route_state::<RouteNotice>();

try_use_route_state::<T>() 找不到 Router context、没有 state 或类型不匹配时返回 Noneuse_route_state::<T>() 是断言型 API,会在缺失或类型不匹配时 panic。

普通 push(path)replace(path) 会清空当前 route state;只有 push_with_statereplace_with_state 会显式携带 state。这能避免从详情页跳到普通页时把旧 state 泄漏到新页面。

Atom 是进程级状态;Router 是 Provider 作用域状态。把默认 Router 存到 Atom 会让多个 RouterProvider 互相污染,也会让测试、嵌入式子应用和局部导航变难。

需要外部可控路由时,优先设计显式 controlled Router API,例如由调用方传入当前 path 和变更回调。只有真正跨 Provider 共享的业务状态,才应该进入 Atom。