乐闻世界logo
搜索文章和话题

How to Implement Routing Management in Yew and What Routing Features Are Supported?

2月19日 16:21

Yew Routing Management Explained

Yew provides powerful routing management features, supporting client-side routing, nested routes, route guards, and other advanced features.

Basic Routing Configuration

1. Install Dependencies

toml
[dependencies] yew = { version = "0.21", features = ["csr"] } yew-router = { version = "0.18" }

2. Define Routes

rust
use yew::prelude::*; use yew_router::prelude::*; #[derive(Clone, Routable, PartialEq)] enum Route { #[at("/")] Home, #[at("/about")] About, #[at("/contact")] Contact, #[at("/users/:id")] User { id: u32 }, #[at("/posts/:post_id/comments/:comment_id")] PostComment { post_id: u32, comment_id: u32 }, #[not_found] #[at("/404")] NotFound, }

3. Create Route Components

rust
#[function_component(Home)] fn home() -> Html { html! { <div> <h1>{ "Welcome Home" }</h1> <p>{ "This is the home page" }</p> </div> } } #[function_component(About)] fn about() -> Html { html! { <div> <h1>{ "About Us" }</h1> <p>{ "Learn more about our company" }</p> </div> } } #[function_component(Contact)] fn contact() -> Html { html! { <div> <h1>{ "Contact Us" }</h1> <p>{ "Get in touch with us" }</p> </div> } } #[derive(Properties, PartialEq)] pub struct UserProps { pub id: u32, } #[function_component(User)] fn user(props: &UserProps) -> Html { html! { <div> <h1>{ format!("User Profile: {}", props.id) }</h1> <p>{ "View user details" }</p> </div> } } #[derive(Properties, PartialEq)] pub struct PostCommentProps { pub post_id: u32, pub comment_id: u32, } #[function_component(PostComment)] fn post_comment(props: &PostCommentProps) -> Html { html! { <div> <h1>{ format!("Post {} - Comment {}", props.post_id, props.comment_id) }</h1> <p>{ "View comment details" }</p> </div> } } #[function_component(NotFound)] fn not_found() -> Html { html! { <div> <h1>{ "404 - Page Not Found" }</h1> <p>{ "The page you're looking for doesn't exist" }</p> </div> } }

4. Set Up Route Switch

rust
#[function_component(Switch)] fn switch() -> Html { let route = use_route::<Route>().unwrap(); match route { Route::Home => html! { <Home /> }, Route::About => html! { <About /> }, Route::Contact => html! { <Contact /> }, Route::User { id } => html! { <User id={*id} /> }, Route::PostComment { post_id, comment_id } => { html! { <PostComment post_id={*post_id} comment_id={*comment_id} /> } } Route::NotFound => html! { <NotFound /> }, } }

5. Create App Component

rust
#[function_component(App)] fn app() -> Html { html! { <BrowserRouter> <div class="app"> <nav class="navbar"> <Link<Route> to={Route::Home}>{ "Home" }</Link<Route>> <Link<Route> to={Route::About}>{ "About" }</Link<Route>> <Link<Route> to={Route::Contact}>{ "Contact" }</Link<Route>> <Link<Route> to={Route::User { id: 1 }}>{ "User 1" }</Link<Route>> </nav> <main class="content"> <Switch /> </main> </div> </BrowserRouter> } } fn main() { yew::Renderer::<App>::new().render(); }

Advanced Routing Features

1. Nested Routes

rust
#[derive(Clone, Routable, PartialEq)] enum Route { #[at("/")] Home, #[at("/dashboard")] Dashboard, #[at("/dashboard/settings")] DashboardSettings, #[at("/dashboard/profile")] DashboardProfile, } #[function_component(Dashboard)] fn dashboard() -> Html { html! { <div class="dashboard"> <aside class="sidebar"> <Link<Route> to={Route::Dashboard}>{ "Overview" }</Link<Route>> <Link<Route> to={Route::DashboardSettings}>{ "Settings" }</Link<Route>> <Link<Route> to={Route::DashboardProfile}>{ "Profile" }</Link<Route>> </aside> <main class="dashboard-content"> <Switch /> </main> </div> } }

2. Route Parameters

rust
#[derive(Clone, Routable, PartialEq)] enum Route { #[at("/products/:category/:id")] Product { category: String, id: u32 }, } #[function_component(Product)] fn product() -> Html { let route = use_route::<Route>().unwrap(); if let Route::Product { category, id } = route { html! { <div> <h1>{ format!("{} - Product {}", category, id) }</h1> </div> } } else { html! { <div>{ "Invalid route" }</div> } } }

3. Query Parameters

rust
use yew_router::hooks::use_location; #[function_component(Search)] fn search() -> Html { let location = use_location().unwrap(); let query_params = location.query::<SearchParams>().unwrap(); html! { <div> <h1>{ "Search Results" }</h1> <p>{ format!("Query: {}", query_params.q) }</p> <p>{ format!("Page: {}", query_params.page) }</p> </div> } } #[derive(Deserialize, Clone, PartialEq)] struct SearchParams { q: String, #[serde(default = "default_page")] page: u32, } fn default_page() -> u32 { 1 }

4. Route Guards

rust
use yew_router::hooks::use_navigator; #[function_component(ProtectedRoute)] fn protected_route() -> Html { let is_authenticated = use_state(|| false); let navigator = use_navigator().unwrap(); // Check authentication status if !*is_authenticated { // Redirect to login page navigator.push(&Route::Login); return html! { <div>{ "Redirecting..." }</div> }; } html! { <div> <h1>{ "Protected Content" }</h1> <p>{ "You are authenticated" }</p> </div> } }
rust
#[function_component(NavigationExample)] fn navigation_example() -> Html { let navigator = use_navigator().unwrap(); let go_home = { let navigator = navigator.clone(); Callback::from(move |_| navigator.push(&Route::Home)) }; let go_back = { let navigator = navigator.clone(); Callback::from(move |_| navigator.back()) }; let go_forward = { let navigator = navigator.clone(); Callback::from(move |_| navigator.forward()) }; let replace_route = { let navigator = navigator.clone(); Callback::from(move |_| navigator.replace(&Route::About)) }; html! { <div> <button onclick={go_home}>{ "Go Home" }</button> <button onclick={go_back}>{ "Go Back" }</button> <button onclick={go_forward}>{ "Go Forward" }</button> <button onclick={replace_route}>{ "Replace Route" }</button> </div> } }

Route Transition Animation

rust
use gloo::timers::callback::Timeout; use std::rc::Rc; use std::cell::RefCell; #[function_component(RouteTransition)] fn route_transition() -> Html { let route = use_route::<Route>().unwrap(); let is_transitioning = use_state(|| false); let current_route = use_state(|| route.clone()); // Listen for route changes let route_effect = { let is_transitioning = is_transitioning.clone(); let current_route = current_route.clone(); use_effect(move || { if *current_route != route { is_transitioning.set(true); // Simulate transition animation let timeout = Timeout::new(300, move || { is_transitioning.set(false); }); timeout.forget(); } || {} }) }; let class = if *is_transitioning { "route-transitioning" } else { "route-active" }; html! { <div class={class}> <Switch /> </div> } }

Route Lazy Loading

rust
use yew_router::Routable; use std::rc::Rc; #[derive(Clone, Routable, PartialEq)] enum Route { #[at("/")] Home, #[at("/lazy")] LazyLoaded, } // Lazy loaded component #[function_component(LazyLoaded)] fn lazy_loaded() -> Html { html! { <div> <h1>{ "Lazy Loaded Component" }</h1> <p>{ "This component was loaded on demand" }</p> </div> } } // Implement lazy loading using conditional rendering #[function_component(LazySwitch)] fn lazy_switch() -> Html { let route = use_route::<Route>().unwrap(); let lazy_component_loaded = use_state(|| false); match route { Route::LazyLoaded => { if !*lazy_component_loaded { lazy_component_loaded.set(true); } html! { <LazyLoaded /> } } _ => html! { <Switch /> }, } }

Best Practices

1. Route Organization

rust
// Define routes in a separate module // src/routes.rs #[derive(Clone, Routable, PartialEq)] pub enum Route { #[at("/")] Home, #[at("/about")] About, // ... other routes } // Define components in separate modules // src/components/home.rs // src/components/about.rs // ...

2. Route Guard Reuse

rust
// src/guards/auth_guard.rs pub fn use_auth_guard() -> bool { let is_authenticated = use_state(|| false); let navigator = use_navigator().unwrap(); if !*is_authenticated { navigator.push(&Route::Login); false } else { true } } // Use guard #[function_component(ProtectedPage)] fn protected_page() -> Html { if !use_auth_guard() { return html! { <div>{ "Redirecting..." }</div> }; } html! { <div> <h1>{ "Protected Content" }</h1> </div> } }

3. Route Error Handling

rust
#[function_component(ErrorBoundary)] fn error_boundary() -> Html { let route = use_route::<Route>().unwrap(); let error = use_state(|| None::<String>); // Error handling logic if let Some(ref err) = *error { html! { <div class="error-boundary"> <h1>{ "Something went wrong" }</h1> <p>{ err }</p> <Link<Route> to={Route::Home}>{ "Go Home" }</Link<Route>> </div> } } else { html! { <Switch /> } } }

Performance Optimization

1. Route Preloading

rust
#[function_component(RoutePreloader)] fn route_preloader() -> Html { let navigator = use_navigator().unwrap(); let preload_route = { let navigator = navigator.clone(); Callback::from(move |_| { // Preload route resources let _ = navigator.push(&Route::LazyLoaded); let _ = navigator.back(); }) }; html! { <div> <button onclick={preload_route}>{ "Preload Route" }</button> </div> } }

2. Route Caching

rust
#[function_component(RouteCache)] fn route_cache() -> Html { let route_cache = use_mut_ref(|| std::collections::HashMap::new()); let route = use_route::<Route>().unwrap(); // Check cache if let Some(cached) = route_cache.borrow().get(&route) { return html! { <div>{ cached.clone() }</div> }; } // Render and cache let content = html! { <Switch /> }; route_cache.borrow_mut().insert(route.clone(), content.clone()); content }
标签:Yew