# Catch All Routes Many modern web apps store parameters within their current path. This allows users to share URLs that link to a specific bit of content. We can create this functionality with catch all routes. > If you want to change what route is active based on the format of the > parameter, see [Matching Routes](./matching.md). > The parameter will be URL decoded. ## Creating a content component We start by creating a component that uses the parameters value. We can get the current state of the router using the [`use_route`] hook. From that state we can extract the current value of our parameter by using a key we will later also define on our route. > It is **VERY IMPORTANT** to drop the object returned by the [`use_route`] > hook once our component finished rendering. Otherwise the entire router will > be frozen. > The [`use_route`] hook can only be used in components nested within a > component that called [`use_router`]. ```rust,no_run # // Hidden lines (like this one) make the documentation tests work. # extern crate dioxus; use dioxus::prelude::*; # extern crate dioxus_router; use dioxus_router::prelude::*; struct Name; fn Greeting(cx: Scope) -> Element { let route = use_route(cx).expect("is nested within a Router component"); let name = route.parameter::() .map(|name| name.clone()) .unwrap_or(String::from("world")); render! { p { "Hello, {name}!" } } } ``` ## Defining the routes Now we can define our route. Unlike a fixed [`Route`], a [`ParameterRoute`] needs two arguments to be created. > Also note that each [`Segment`] can have exactly one parameter or > [fallback route](./fallback.md). > > For that reason, the example below would not work in practice, but showing > both forms (explicit and short) is more important for this example. ```rust,no_run # // Hidden lines (like this one) make the documentation tests work. # extern crate dioxus; # use dioxus::prelude::*; # extern crate dioxus_router; # use dioxus_router::prelude::*; # fn Greeting(cx: Scope) -> Element { unimplemented!() } # struct Name; fn App(cx: Scope) -> Element { use_router( cx, &|| RouterConfiguration { ..Default::default() }, &|| { Segment::empty() .catch_all(ParameterRoute::content::(comp(Greeting))) .catch_all((comp(Greeting), Name { })) // same in short } ); // ... # unimplemented!() } ``` ## Interaction with other routes Each individual [`Segment`] can only ever have one active route. This means that when a [`Segment`] has more than just a catch all route, the router has to decide which is active. It does that this way: 0. If the segment is not specified (i.e. `/`), then the index route will be active. 1. If a [_fixed_](./index.md#fixed-routes) route matches the current path, it will be active. 2. If a [_matching_ route](./matching.md) matches the current path, it will be active. _Matching_ routes are checked in the order they are defined. 3. If neither a _fixed_ nor a _matching_ route is active, the _catch all_ route or [_fallback_ route](./fallback.md) will be. Step 0 means that if we want a parameter to be empty, that needs to be specified by the path, i.e. `//`. > Be careful with using catch all routes on the root [`Segment`]. Navigating to > paths starting with `//` will **NOT** work. This is not a limitation of the > router, but rather of how relative URLs work. > > If you absolutely need an empty parameter on the root [`Segment`], a URL like > this _could_ work: > - `https://your-site.example//` for web sites > - `dioxus://index.html//` for desktop apps ## Full Code ```rust # // Hidden lines (like this one) make the documentation tests work. # extern crate dioxus; # use dioxus::prelude::*; # extern crate dioxus_router; # use dioxus_router::{history::MemoryHistory, prelude::*}; # extern crate dioxus_ssr; # struct Name; fn Greeting(cx: Scope) -> Element { let route = use_route(cx).expect("is nested within a Router component"); let name = route.parameter::() .map(|name| name.clone()) .unwrap_or(String::from("world")); render! { p { "Hello, {name}!" } } } fn App(cx: Scope) -> Element { let routes = use_router( cx, &|| RouterConfiguration { # synchronous: true, # history: Box::new(MemoryHistory::with_initial_path("/Dioxus").unwrap()), ..Default::default() }, &|| Segment::empty().catch_all((comp(Greeting), Name { })) ); // ... render! { Outlet { } } } # # let mut vdom = VirtualDom::new(App); # vdom.rebuild(); # assert_eq!( # dioxus_ssr::render(&vdom), # "

Hello, Dioxus!

" # ); ``` [`ParameterRoute`]: https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.ParameterRoute.html [`Route`]: https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Route.html [`Segment`]: https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html [`use_route`]: https://docs.rs/dioxus-router/latest/dioxus_router/hooks/fn.use_route.html [`use_router`]: https://docs.rs/dioxus-router/latest/dioxus_router/hooks/fn.use_router.html