Navigation Targets
In the previous chapter we learned how to create links to pages within our app.
We told them where to go using the target
property. This property takes a
NavigationTarget
.
What is a navigation target?
A NavigationTarget
is similar to the href
of an HTML anchor element.It
tells the router where to navigate to. The Dioxus Router knows three kinds of
navigation targets:
Internal
: we already saw that. It's basically anhref
, but cannot link to content outside our app.External
: This works exactly like an HTML anchorshref
. In fact, it is just passed through. Don't use this for in-app navigation as it'll trigger a page reload by the browser.Named
: this is the most interesting form of navigation target. We'll look at it in detail in this chapter.
External navigation
If we need a link to an external page we can do it like this:
#![allow(unused)] fn main() { // 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 GoToDioxus(cx: Scope) -> Element { render! { Link { target: NavigationTarget::External("https://dioxuslabs.com".into()), "Explicit ExternalTarget target" } Link { target: "https://dioxuslabs.com", // short form "Implicit ExternalTarget target" } } } }
Note that we can use a
str
, just like withInternal
s. The router will convert astr
to anExternal
if the URL is absolute.
Named navigation
When defining our routes, we can optionally give them unique static names. This is required for a feature we call named navigation.
Up to now, when creating links we told the router the exact path to go to. With named navigation we instead give it a name, and let it figure out the path.
This has several advantages:
- We don't have to remember absolute paths or care about what the current path is.
- Changing paths later on won't break internal links.
- Paths can easily be localized without affecting app logic.
- The compiler makes sure we don't have typos.
Let's try that now! First, we give our blog post route a name. We can reuse our
BlogPost
component as a name.
#![allow(unused)] fn main() { // 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 Blog(cx: Scope) -> Element { unimplemented!() } fn BlogList(cx: Scope) -> Element { unimplemented!() } struct PostId; fn BlogPost(cx: Scope) -> Element { unimplemented!() } fn Home(cx: Scope) -> Element { unimplemented!() } fn PageNotFound(cx: Scope) -> Element { unimplemented!() } struct BlogPostName; fn App(cx: Scope) -> Element { use_router( cx, &|| RouterConfiguration::default(), &|| { Segment::content(comp(Home)) .fixed("blog", Route::content(comp(Blog)).nested( Segment::content(comp(BlogList)).catch_all( ParameterRoute::content::<PostId>(comp(BlogPost)) .name::<BlogPostName>() // this is new ) )) .fallback(comp(PageNotFound)) } ); // ... unimplemented!() } }
Now we can change the targets of the links in our BlogList
component.
#![allow(unused)] fn main() { // 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 PostId; struct BlogPostName; fn BlogPost(cx: Scope) -> Element { unimplemented!() } fn BlogList(cx: Scope) -> Element { render! { h2 { "Choose a post" } ul { li { Link { target: named::<BlogPostName>().parameter::<PostId>("1"), "Read the first blog post" } } li { Link { target: named::<BlogPostName>() .parameter::<PostId>("1") .query("query"), "Read the second blog post" } } } } } }
As you can see, a Named
requires three fields:
- the name to navigate to
- a
Vec
containing all parameters that need to be inserted into the path - optionally a query string to use.
The special root index name
Whether we define any names or not, the router always knows about the
RootIndex
name. Navigating to it tells the router to go to /
.
We can change the link in our NavBar
component to take advantage of that.
#![allow(unused)] fn main() { // 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 NavBar(cx: Scope) -> Element { render! { nav { ul { li { Link { target: named::<RootIndex>(), "Home" } } li { Link { target: "/blog", "Blog" } } } } } } }