add rewritten router book and fix features code
This commit is contained in:
38 files changed
+2909
-449
No files matched your search
@@ -0,0 +1,263 @@
|
||||
# Building a Nest
|
||||
Not a bird's nest! A nest of routes!
|
||||
|
||||
In this chapter we will begin to build the blog portion of our site which will
|
||||
include links, nested URLs, and URL parameters. We will also explore the use
|
||||
case of rendering components directly in the [`Router`].
|
||||
|
||||
## Site Navigation
|
||||
Our site visitors won't know all the available pages and blogs on our site so we
|
||||
should provide a navigation bar for them.
|
||||
Let's create a new `NavBar` component:
|
||||
```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 NavBar(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
nav {
|
||||
ul { }
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
Our navbar will be a list of links going between our pages. We could always use
|
||||
an HTML anchor element but that would cause our page to reload unnecessarily.
|
||||
Instead we want to use the [`Link`] component provided by Dioxus Router.
|
||||
|
||||
The [`Link`] is similar to a regular `a` tag. It takes a target (for now a path,
|
||||
more on other targets later) and an element. Let's add our links
|
||||
|
||||
```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 NavBar(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
nav {
|
||||
ul {
|
||||
// new stuff starts here
|
||||
li { Link { target: InternalTarget(String::from("/")), "Home" } }
|
||||
li { Link {
|
||||
target: "/blog", // short form
|
||||
"Blog"
|
||||
} }
|
||||
// new stuff ends here
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
> Using this method, the [`Link`] component only works for links within our
|
||||
> application. To learn more about navigation targets see
|
||||
> [here](./navigation-targets.md).
|
||||
|
||||
And finally, we add the navbar component in our app component:
|
||||
```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 Home(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn NavBar(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn PageNotFound(cx: Scope) -> Element { unimplemented!() }
|
||||
#
|
||||
fn App(cx: Scope) -> Element {
|
||||
let routes = use_segment(&cx, || {
|
||||
Segment::new()
|
||||
.index(Home as Component)
|
||||
.fallback(PageNotFound as Component)
|
||||
});
|
||||
|
||||
cx.render(rsx! {
|
||||
Router {
|
||||
routes: routes.clone(),
|
||||
NavBar { } // this is new
|
||||
Outlet { }
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
Now you should see a list of links near the top of your page. Click on one and
|
||||
you should seamlessly travel between pages.
|
||||
|
||||
### Active Link Styling
|
||||
You might want to style links differently, when their page is currently open.
|
||||
To achieve this, we can tell the [`Link`] to give its internal `a` tag a class
|
||||
in that case.
|
||||
|
||||
```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 NavBar(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
nav {
|
||||
ul {
|
||||
li { Link {
|
||||
target: InternalTarget(String::from("/")),
|
||||
active_class: "active", // this is new
|
||||
"Home"
|
||||
} }
|
||||
li { Link {
|
||||
target: "/blog",
|
||||
active_class: "active", // this is new
|
||||
"Blog"
|
||||
} }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
> This will not be reflected in the [full example code](./full-code.md).
|
||||
|
||||
## URL Parameters and Nested Routes
|
||||
Many websites such as GitHub put parameters in their URL. For example,
|
||||
`https://github.com/DioxusLabs` utilizes the text after the domain to
|
||||
dynamically search and display content about an organization.
|
||||
|
||||
We want to store our blogs in a database and load them as needed. This'll help
|
||||
prevent our app from being bloated therefor providing faster load times. We also
|
||||
want our users to be able to send people a link to a specific blog post.
|
||||
|
||||
We could utilize a search page that loads a blog when clicked but then our users
|
||||
won't be able to share our blogs easily. This is where URL parameters come in.
|
||||
|
||||
The path to our blog will look like `/blog/myBlogPage`, `myBlogPage` being the
|
||||
URL parameter.
|
||||
|
||||
First, lets create a component that wraps around all blog content. This allows
|
||||
us to add a heading that tells the user they are on the blog.
|
||||
```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 Blog(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
h1 { "Blog" }
|
||||
Outlet {}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
> Note the `Outlet { }` component. For the components of a nested route to be
|
||||
> rendered, we need an equally nested outlet. For more details, see the
|
||||
> [nested routes](../features/routes/nested.md) chapter of the features section.
|
||||
|
||||
Now we'll create another index component, that'll be displayed when no blog post
|
||||
is selected:
|
||||
```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 BlogList(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
h2 { "Choose a post" }
|
||||
ul {
|
||||
li { Link {
|
||||
target: "/blog/1",
|
||||
"Read the first blog post"
|
||||
} }
|
||||
li { Link {
|
||||
target: "/blog/2",
|
||||
"Read the second blog post"
|
||||
} }
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
We also need to create a component that displays an actual blog post. Within
|
||||
this component we can use the `use_route` hook to gain access to our URL
|
||||
parameters:
|
||||
```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 BlogPost(cx: Scope) -> Element {
|
||||
let route = use_route(&cx).unwrap();
|
||||
|
||||
let post_id = route.parameters.get("post_id");
|
||||
let post = post_id
|
||||
.map(|id| id.to_string())
|
||||
.unwrap_or(String::from("unknown"));
|
||||
|
||||
cx.render(rsx! {
|
||||
h2 { "Blog Post: {post}"}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
Finally, let's tell our router about those components.
|
||||
```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 Blog(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn BlogList(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn BlogPost(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn Home(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn NavBar(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn PageNotFound(cx: Scope) -> Element { unimplemented!() }
|
||||
#
|
||||
fn App(cx: Scope) -> Element {
|
||||
let routes = use_segment(&cx, || {
|
||||
Segment::default()
|
||||
.index(Home as Component)
|
||||
// new stuff starts here
|
||||
.fixed(
|
||||
"blog",
|
||||
Route::new(Blog as Component).nested(
|
||||
Segment::default()
|
||||
.index(BlogList as Component)
|
||||
.catch_all(("post_id", BlogPost as Component))
|
||||
),
|
||||
)
|
||||
// new stuff ends here
|
||||
.fallback(PageNotFound as Component)
|
||||
});
|
||||
|
||||
cx.render(rsx! {
|
||||
Router {
|
||||
routes: routes.clone(),
|
||||
NavBar { }
|
||||
Outlet { }
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
That's it! If you head to `/blog/1` you should see our sample post.
|
||||
|
||||
## Conclusion
|
||||
In this chapter we utilized Dioxus Router's Link, URL Parameter, and `use_route`
|
||||
functionality to build the blog portion of our application. In the next chapter,
|
||||
we will go over how navigation targets (like the one we passed to our links)
|
||||
work.
|
||||
|
||||
[`Link`]: https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html
|
||||
[`Router`]: https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Router.html
|
||||
@@ -0,0 +1,91 @@
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_router::prelude::*;
|
||||
|
||||
fn main() {
|
||||
dioxus_web::launch(App);
|
||||
}
|
||||
|
||||
fn App(cx: Scope) -> Element {
|
||||
let routes = use_segment(&cx, || {
|
||||
Segment::default()
|
||||
.index(Home as Component)
|
||||
.fixed(
|
||||
"blog",
|
||||
Route::new(Blog as Component).nested(
|
||||
Segment::default().index(BlogList as Component).catch_all(
|
||||
ParameterRoute::new("post_id", BlogPost as Component).name(BlogPost),
|
||||
),
|
||||
),
|
||||
)
|
||||
.fixed("myblog", "/blog")
|
||||
.fallback(PageNotFound as Component)
|
||||
});
|
||||
|
||||
cx.render(rsx! {
|
||||
Router {
|
||||
routes: routes.clone(),
|
||||
NavBar {}
|
||||
Outlet {}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn NavBar(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
nav {
|
||||
ul {
|
||||
li { Link { target: (RootIndex, []), "Home" } }
|
||||
li { Link { target: "/blog", "Blog" } }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn Home(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
h1 { "Welcome to the Dioxus Blog!" }
|
||||
})
|
||||
}
|
||||
|
||||
fn Blog(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
h1 { "Blog" }
|
||||
Outlet {}
|
||||
})
|
||||
}
|
||||
|
||||
fn BlogList(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
h2 { "Choose a post" }
|
||||
ul {
|
||||
li { Link {
|
||||
target: (BlogPost, [("post_id", String::from("1"))]),
|
||||
"Read the first blog post"
|
||||
} }
|
||||
li { Link {
|
||||
target: (BlogPost, [("post_id", String::from("2"))]),
|
||||
"Read the second blog post"
|
||||
} }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn BlogPost(cx: Scope) -> Element {
|
||||
let route = use_route(&cx).unwrap();
|
||||
|
||||
let post_id = route.parameters.get("post_id");
|
||||
let post = post_id
|
||||
.map(|id| id.to_string())
|
||||
.unwrap_or(String::from("unknown"));
|
||||
|
||||
cx.render(rsx! {
|
||||
h2 { "Blog Post: {post}"}
|
||||
})
|
||||
}
|
||||
|
||||
fn PageNotFound(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
h1 { "Page not found" }
|
||||
p { "We are terribly sorry, but the page you requested doesn't exist." }
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
# Creating Our First Route
|
||||
In this chapter, we will start utilizing Dioxus Router and add a homepage and a
|
||||
404 page to our project.
|
||||
|
||||
## Fundamentals
|
||||
Dioxus Router works based on a [`Router`] component, a route definition in
|
||||
regular rust and [`Outlet`] components. If you've ever used [Vue Router],
|
||||
you should feel at home with Dioxus Router.
|
||||
|
||||
First we need an actual page to route to! Let's add a homepage component:
|
||||
```rust,no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
#
|
||||
fn Home(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
h1 { "Welcome to the Dioxus Blog!" }
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## To Route or Not to Route
|
||||
We want to use Dioxus Router to separate our application into different "pages".
|
||||
Dioxus Router will then determine which page to render based on the URL path.
|
||||
|
||||
To start using Dioxus Router, we need to use the [`Router`] component. All hooks
|
||||
and other components the Router provides can only be used as a descendant of
|
||||
a [`Router`] component.
|
||||
|
||||
However, before we can add the [`Router`] we need to describe our routes in a
|
||||
type it can understand:
|
||||
```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 Home(cx: Scope) -> Element { unimplemented!() }
|
||||
|
||||
fn App(cx: Scope) -> Element {
|
||||
let routes = use_segment(&cx, || {
|
||||
// we want our home page component to render as an index
|
||||
Segment::default().index(Home as Component)
|
||||
});
|
||||
|
||||
cx.render(rsx! {
|
||||
p { "Hello, Dioxus!"}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
Now we can replace the `p { "Hello, Dioxus!" }` with our [`Router`]. We also
|
||||
need to tell it where to render the content of the active route. Therefore we
|
||||
nest an [`Outlet`] inside it.
|
||||
```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 Home(cx: Scope) -> Element { unimplemented!() }
|
||||
|
||||
fn App(cx: Scope) -> Element {
|
||||
let routes = use_segment(&cx, || {
|
||||
Segment::default().index(Home as Component)
|
||||
});
|
||||
|
||||
cx.render(rsx! {
|
||||
// new stuff starts here
|
||||
Router {
|
||||
routes: routes.clone() // pass in the routes we prepared before
|
||||
Outlet { }
|
||||
}
|
||||
// new stuff ends here
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
If you head to your application's browser tab, you should now see the text
|
||||
`Welcome to Dioxus Blog!` when on the root URL (`http://localhost:8080/`). If
|
||||
you enter a different path for the URL, nothing should be displayed.
|
||||
|
||||
This is because we told Dioxus Router to render the `Home` component only when
|
||||
the URL path is `/`. The _index_ functionality we used basically emulates how
|
||||
web servers treat `index.html` files.
|
||||
|
||||
## What if a Route Doesn't Exist?
|
||||
In our example Dioxus Router doesn't render anything. Many sites also have a
|
||||
"404" page for when a URL path leads to nowhere. Dioxus Router can do this too!
|
||||
|
||||
First, we create a new `PageNotFound` component.
|
||||
```rust,no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
#
|
||||
fn PageNotFound(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
h1 { "Page not found" }
|
||||
p { "We are terribly sorry, but the page you requested doesn't exist." }
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
Now to tell Dioxus Router to render our new component when no route exists.
|
||||
```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 Home(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn PageNotFound(cx: Scope) -> Element { unimplemented!() }
|
||||
#
|
||||
fn App(cx: Scope) -> Element {
|
||||
let routes = use_segment(&cx, || {
|
||||
Segment::default()
|
||||
.index(Home as Component)
|
||||
.fallback(PageNotFound as Component) // this is new
|
||||
});
|
||||
|
||||
cx.render(rsx! {
|
||||
Router {
|
||||
routes: routes.clone(),
|
||||
Outlet { }
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
Now when you go to a route that doesn't exist, you should see the page not found
|
||||
text.
|
||||
|
||||
## Conclusion
|
||||
In this chapter we learned how to create a route and tell Dioxus Router what
|
||||
component to render when the URL path is `/`. We also created a 404 page to
|
||||
handle when a route doesn't exist. Next, we'll create the blog portion of our
|
||||
site. We will utilize nested routes and URL parameters.
|
||||
|
||||
[`Outlet`]: https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html
|
||||
[`Router`]: https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Router.html
|
||||
[Vue Router]: https://router.vuejs.org/
|
||||
@@ -0,0 +1,9 @@
|
||||
# Full Code
|
||||
|
||||
```rust,no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# extern crate dioxus_router;
|
||||
# extern crate dioxus_web;
|
||||
{{#include example.rs}}
|
||||
```
|
||||
@@ -0,0 +1,30 @@
|
||||
# Overview
|
||||
|
||||
In this guide you'll learn to effectively use Dioxus Router whether you're
|
||||
building a small todo app or the next FAANG company. We will create a small
|
||||
website with a blog, homepage, and more!
|
||||
|
||||
> To follow along with the router example, you'll need a working Dioxus app.
|
||||
> Check out the [Dioxus book][db] to get started.
|
||||
|
||||
> Make sure to add Dioxus Router as a dependency, as explained in the
|
||||
> [introduction](../index.md).
|
||||
|
||||
## You'll learn how to
|
||||
- Create routes and render "pages".
|
||||
- Utilize nested routes, create a navigation bar, and render content for a
|
||||
set of routes.
|
||||
- Gather URL parameters to dynamically display content.
|
||||
- Redirect your visitors wherever you want.
|
||||
|
||||
> **Disclaimer**
|
||||
>
|
||||
> The example will only display the features of Dioxus Router. It will not
|
||||
> include any actual functionality. To keep things simple we will only be using
|
||||
> a single file, this is not the recommended way of doing things with a real
|
||||
> application.
|
||||
|
||||
You can find the complete application in the [full code](./full-code.md)
|
||||
chapter.
|
||||
|
||||
[db]: https://dioxuslabs.com/guide/
|
||||
@@ -0,0 +1,151 @@
|
||||
# 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:
|
||||
- [`InternalTarget`]: we already saw that. It's basically an `href`, but cannot
|
||||
link to content outside our app.
|
||||
- [`ExternalTarget`]: This works exactly like an HTML anchors `href`. 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.
|
||||
- [`NamedTarget`]: 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:
|
||||
```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 GoToDioxus(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
Link {
|
||||
target: ExternalTarget(String::from("https://dioxuslabs.com")),
|
||||
"Explicit ExternalTarget target"
|
||||
}
|
||||
Link {
|
||||
target: "https://dioxuslabs.com", // short form
|
||||
"Implicit ExternalTarget target"
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
> Note that we can use a `str`, just like with [`InternalTarget`]s. The router
|
||||
> will convert a `str` to an [`ExternalTarget`] 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
|
||||
|
||||
Let's try that now! First, we give our blog post route a name. We can reuse our
|
||||
`BlogPost` component as a name.
|
||||
```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 Blog(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn BlogList(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn BlogPost(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn Home(cx: Scope) -> Element { unimplemented!() }
|
||||
#
|
||||
fn App(cx: Scope) -> Element {
|
||||
let routes = use_segment(&cx, || {
|
||||
Segment::default()
|
||||
.index(Home as Component)
|
||||
.fixed(
|
||||
"blog",
|
||||
Route::new(Blog as Component).nested(
|
||||
Segment::default().index(BlogList as Component).catch_all(
|
||||
// notice the name at the end of the line
|
||||
ParameterRoute::new("post_id", BlogPost as Component).name(BlogPost),
|
||||
),
|
||||
),
|
||||
)
|
||||
});
|
||||
|
||||
// ...
|
||||
# unimplemented!()
|
||||
}
|
||||
```
|
||||
|
||||
Now we can change the targets of the links in our `BlogList` component.
|
||||
```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 BlogPost(cx: Scope) -> Element { unimplemented!() }
|
||||
#
|
||||
fn BlogList(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
h2 { "Choose a post" }
|
||||
ul {
|
||||
li { Link {
|
||||
target: (BlogPost, [("post_id", String::from("1"))]),
|
||||
"Read the first blog post"
|
||||
} }
|
||||
li { Link {
|
||||
target: (BlogPost, [("post_id", String::from("2"))], "query"),
|
||||
"Read the second blog post"
|
||||
} }
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, a [`NamedTarget`] requires three fields:
|
||||
1. the name to navigate to
|
||||
2. a `Vec` containing all parameters that need to be inserted into the path
|
||||
3. 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.
|
||||
```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 NavBar(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
nav {
|
||||
ul {
|
||||
li { Link { target: (RootIndex, []), "Home" } }
|
||||
li { Link { target: "/blog", "Blog" } }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
[`ExternalTarget`]: https://docs.rs/dioxus-router/latest/dioxus_router/navigation/enum.NavigationTarget.html#variant.ExternalTarget
|
||||
[`InternalTarget`]: https://docs.rs/dioxus-router/latest/dioxus_router/navigation/enum.NavigationTarget.html#variant.InternalTarget
|
||||
[`NamedTarget`]: https://docs.rs/dioxus-router/latest/dioxus_router/navigation/enum.NavigationTarget.html#variant.NamedTarget
|
||||
[`NavigationTarget`]: https://docs.rs/dioxus-router/latest/dioxus_router/navigation/enum.NavigationTarget.html
|
||||
[`RootIndex`]: https://docs.rs/dioxus-router/latest/dioxus_router/names/struct.RootIndex.html
|
||||
@@ -0,0 +1,64 @@
|
||||
# Redirection Perfection
|
||||
You're well on your way to becoming a routing master!
|
||||
|
||||
In this chapter we will cover utilizing redirects so you can take Rickrolling to
|
||||
the next level.
|
||||
|
||||
## What Is This Redirect Thing?
|
||||
A redirect is very simple. When dioxus encounters a redirect while finding out
|
||||
what components to render, it will redirect the user to the target of the
|
||||
redirect.
|
||||
|
||||
As a simple example, let's say you want user to still land on your blog, even
|
||||
if they used the path `/myblog`.
|
||||
|
||||
All we need to do is update our route definition in our app component:
|
||||
```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 Blog(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn BlogList(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn BlogPost(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn Home(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn NavBar(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn PageNotFound(cx: Scope) -> Element { unimplemented!() }
|
||||
# fn App(cx: Scope) -> Element {
|
||||
let routes = use_segment(&cx, || {
|
||||
Segment::new()
|
||||
.index(Home as Component)
|
||||
.fixed(
|
||||
"blog",
|
||||
Route::new(Blog as Component).nested(
|
||||
Segment::new().index(BlogList as Component).catch_all(
|
||||
ParameterRoute::new("post_id", BlogPost as Component).name(BlogPost)
|
||||
),
|
||||
),
|
||||
)
|
||||
.fixed("myblog", "/blog") // this is new
|
||||
.fallback(PageNotFound as Component)
|
||||
});
|
||||
# unimplemented!()
|
||||
# }
|
||||
```
|
||||
|
||||
That's it! Now your users will be redirected to the blog.
|
||||
|
||||
Notice that the `"/blog"` `str` is a [navigation target](./navigation-targets.md).
|
||||
We could also use external or named targets.
|
||||
|
||||
### Conclusion
|
||||
Well done! You've completed the Dioxus Router guide book. You've built a small
|
||||
application and learned about the many things you can do with Dioxus Router.
|
||||
To continue your journey, you can find a list of challenges down below, or you
|
||||
can check out the [API reference](https://docs.rs/dioxus-router/).
|
||||
|
||||
### Challenges
|
||||
- Organize your components into seperate files for better maintainability.
|
||||
- Give your app some style if you haven't already.
|
||||
- Build an about page so your visitors know who you are.
|
||||
- Add a user system that uses URL parameters.
|
||||
- Create a simple admin system to create, delete, and edit blogs.
|
||||
- If you want to go to the max, hook up your application to a rest API and database.
|
||||
Reference in new issue
Block a user