update the router guide
This commit is contained in:
1 parent
67992f7da9
commit
0d3ea377ce
63 files changed
+615
-1705
No files matched your search
@@ -2,30 +2,8 @@
|
||||
|
||||
[Introduction](./index.md)
|
||||
|
||||
# Features
|
||||
- [Adding the Router to Your Application](./features/index.md)
|
||||
- [Defining Routes](./features/routes/index.md)
|
||||
- [Nested Routes](./features/routes/nested.md)
|
||||
- [Catch All Routes](./features/routes/catch_all.md)
|
||||
- [Matching Routes](./features/routes/matching.md)
|
||||
- [Fallback Routes (404 page)](./features/routes/fallback.md)
|
||||
- [Multiple Components & Redirects](./features/routes/multiple-and-redirect.md)
|
||||
- [Outlets](./features/outlets.md)
|
||||
- [Links & Navigation](./features/navigation/index.md)
|
||||
- [Named Navigation](./features/navigation/name.md)
|
||||
- [External Navigation](./features/navigation/external.md)
|
||||
- [Programmatic Navigation](./features/navigation/programmatic.md)
|
||||
- [Query](./features/query.md)
|
||||
- [Navigation Failures](./features/failures/index.md)
|
||||
- [Named Navigation Failure](./features/failures/named.md)
|
||||
- [External Navigation Failure](./features/failures/external.md)
|
||||
- [Redirection Limit Failure](./features/failures/redirection-limit.md)
|
||||
- [History Providers](./features/history-providers.md)
|
||||
- [History Buttons](./features/history-buttons.md)
|
||||
- [Sitemap Generation](./features/sitemap-generation.md)
|
||||
- [Routing Update Callback](./features/routing-update-callback.md)
|
||||
|
||||
# Example Project
|
||||
|
||||
- [Overview](./example/index.md)
|
||||
- [Creating Our First Route](./example/first-route.md)
|
||||
- [Building a Nest](./example/building-a-nest.md)
|
||||
|
||||
@@ -1,137 +1,60 @@
|
||||
# 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 component calling [`use_router`].
|
||||
In this chapter, we will begin to build the blog portion of our site which will
|
||||
include links, nested routes, and route parameters.
|
||||
|
||||
## 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.
|
||||
should provide a navigation bar for them. Our navbar will be a list of links going between our pages.
|
||||
|
||||
We want our navbar component to be rendered on several different pages on our site. Instead of duplicating the code, we can create a component that wraps all children routes. This is called a layout component. To tell the router where to render the child routes, we use the [`Outlet`] component.
|
||||
|
||||
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 {
|
||||
render! {
|
||||
nav {
|
||||
ul { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```rust, no_run
|
||||
{{#include ../../examples/nested_routes.rs:nav}}
|
||||
```
|
||||
|
||||
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.
|
||||
Next, let's add our `NavBar` component as a layout to our Route enum:
|
||||
|
||||
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
|
||||
{{#include ../../examples/nested_routes.rs: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::*;
|
||||
#
|
||||
fn NavBar(cx: Scope) -> Element {
|
||||
render! {
|
||||
nav {
|
||||
ul {
|
||||
// new stuff starts here
|
||||
li { Link {
|
||||
target: NavigationTarget::Internal(String::from("/")),
|
||||
"Home"
|
||||
} }
|
||||
li { Link {
|
||||
target: "/blog", // short form
|
||||
"Blog"
|
||||
} }
|
||||
// new stuff ends here
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
To add links to our `NavBar`, we could always use an HTML anchor element but that has two issues:
|
||||
|
||||
1. It causes a full-page reload
|
||||
2. We can accidentally link to a page that doesn't exist
|
||||
|
||||
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 and children.
|
||||
|
||||
Unlike a regular `<a>` tag, we can pass in our Route enum as the target. Because we annotated our routes with the [`route(path)`] attribute, the [`Link`] will know how to generate the correct URL. If we use the Route enum, the rust compiler will prevent us from linking to a page that doesn't exist.
|
||||
|
||||
Let's add our links:
|
||||
|
||||
```rust, no_run
|
||||
{{#include ../../examples/links.rs:nav}}
|
||||
```
|
||||
|
||||
> 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 {
|
||||
use_router(
|
||||
cx,
|
||||
&|| RouterConfiguration::default(),
|
||||
&|| Segment::content(comp(Home)).fallback(comp(PageNotFound))
|
||||
);
|
||||
|
||||
render! {
|
||||
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 {
|
||||
render! {
|
||||
nav {
|
||||
ul {
|
||||
li { Link {
|
||||
target: NavigationTarget::Internal(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
|
||||
We want to store our blogs in a database and load them as needed. We also
|
||||
want our users to be able to send people a link to a specific blog post.
|
||||
Instead of listing all of the blog titles at compile time, we can make a dynamic route.
|
||||
|
||||
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.
|
||||
@@ -139,124 +62,38 @@ 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 {
|
||||
render! {
|
||||
h1 { "Blog" }
|
||||
Outlet {}
|
||||
}
|
||||
}
|
||||
```
|
||||
First, let's create a layout component (similar to the navbar) that wraps the blog content. This allows us to add a heading that tells the user they are on the blog.
|
||||
|
||||
> 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.
|
||||
```rust, no_run
|
||||
{{#include ../../examples/dynamic_route.rs:blog}}
|
||||
```
|
||||
|
||||
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 {
|
||||
render! {
|
||||
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"
|
||||
} }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```rust, no_run
|
||||
{{#include ../../examples/dynamic_route.rs:blog_list}}
|
||||
```
|
||||
|
||||
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::*;
|
||||
#
|
||||
struct PostId;
|
||||
We also need to create a component that displays an actual blog post. This component will accept the URL parameters as props:
|
||||
|
||||
fn BlogPost(cx: Scope) -> Element {
|
||||
let route = use_route(cx).unwrap();
|
||||
|
||||
let post_id = route.parameter::<PostId>();
|
||||
let post = post_id
|
||||
.map(|id| id.to_string())
|
||||
.unwrap_or(String::from("unknown"));
|
||||
|
||||
render! {
|
||||
h2 { "Blog Post: {post}"}
|
||||
}
|
||||
}
|
||||
```rust, no_run
|
||||
{{#include ../../examples/dynamic_route.rs:blog_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!() }
|
||||
# struct PostId;
|
||||
# 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 {
|
||||
use_router(
|
||||
cx,
|
||||
&|| RouterConfiguration::default(),
|
||||
&|| {
|
||||
Segment::content(comp(Home))
|
||||
// new stuff starts here
|
||||
.fixed("blog", Route::content(comp(Blog)).nested(
|
||||
Segment::content(comp(BlogList))
|
||||
.catch_all((comp(BlogPost), PostId { }))
|
||||
))
|
||||
// new stuff ends here
|
||||
.fallback(comp(PageNotFound))
|
||||
}
|
||||
);
|
||||
Finally, let's tell our router about those components:
|
||||
|
||||
render! {
|
||||
NavBar { }
|
||||
Outlet { }
|
||||
}
|
||||
}
|
||||
```rust, no_run
|
||||
{{#include ../../examples/dynamic_route.rs:router}}
|
||||
```
|
||||
|
||||
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`
|
||||
|
||||
In this chapter, we utilized Dioxus Router's Link, and Route Parameter
|
||||
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
|
||||
[`use_router`]: https://docs.rs/dioxus-router/latest/dioxus_router/hooks/fn.use_router.html
|
||||
[`Link`]: https://docs.rs/dioxus-router/latest/dioxus_router/prelude/fn.GenericLink<R>.html
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,123 +1,62 @@
|
||||
# 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 [`use_router`] hook, a route definition in pure
|
||||
rust and [`Outlet`] components. If you've ever used [Vue Router], you should
|
||||
feel right 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 {
|
||||
render! {
|
||||
h1 { "Welcome to the Dioxus Blog!" }
|
||||
}
|
||||
}
|
||||
The core of the Dioxus Router is the [`Routable`] macro and the [`Router`] component.
|
||||
|
||||
First, we need an actual page to route to! Let's add a homepage component:
|
||||
|
||||
```rust, no_run
|
||||
{{#include ../../examples/first_route.rs:home}}
|
||||
```
|
||||
|
||||
## 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 [`use_router`] hook. All other
|
||||
hooks and components the router provides can only be used as a descendant of a
|
||||
component calling [`use_router`].
|
||||
To start using Dioxus Router, we need to use the [`Routable`] macro.
|
||||
|
||||
The [`use_router`] hook takes three arguments:
|
||||
1. `cx`, which is a common argument for all hooks.
|
||||
2. A [`RouterConfiguration`], which allows us to modify its behavior.
|
||||
3. A definition of all routes the application contains, in the form of its root
|
||||
[`Segment`].
|
||||
The [`Routable`] macro takes an enum with all of the possible routes in our application. Each variant of the enum represents a route and must be annotated with the [`route(path)`] attribute.
|
||||
|
||||
```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 {
|
||||
use_router(
|
||||
cx,
|
||||
&|| RouterConfiguration::default(),
|
||||
&|| Segment::content(comp(Home))
|
||||
);
|
||||
|
||||
render! {
|
||||
Outlet { }
|
||||
}
|
||||
}
|
||||
```rust, no_run
|
||||
{{#include ../../examples/first_route.rs:router}}
|
||||
```
|
||||
|
||||
All other hooks and components the router provides can only be used as a descendant of a [`Router`] component.
|
||||
|
||||
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_ (`Segment::content()`) functionality we used
|
||||
basically emulates how web servers treat `index.html` files.
|
||||
the URL path is `/`.
|
||||
|
||||
## 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!
|
||||
|
||||
In our example, when a route doesn't exist Dioxus Router doesn't render anything. Many sites also have a "404" page when a path does not exist. Let's add one to our site.
|
||||
|
||||
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 {
|
||||
render! {
|
||||
h1 { "Page not found" }
|
||||
p { "We are terribly sorry, but the page you requested doesn't exist." }
|
||||
}
|
||||
}
|
||||
|
||||
```rust, no_run
|
||||
{{#include ../../examples/catch_all.rs:fallback}}
|
||||
```
|
||||
|
||||
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 {
|
||||
use_router(
|
||||
cx,
|
||||
&|| RouterConfiguration::default(),
|
||||
&|| {
|
||||
Segment::content(comp(Home))
|
||||
.fallback(comp(PageNotFound)) // this is new
|
||||
}
|
||||
);
|
||||
Next, register the route in the Route enum to match if all other routes fail.
|
||||
|
||||
render! {
|
||||
Outlet { }
|
||||
}
|
||||
}
|
||||
```rust, no_run
|
||||
{{#include ../../examples/catch_all.rs:router}}
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
[`RouterConfiguration`]: https://docs.rs/dioxus-router/latest/dioxus_router/hooks/struct.RouterConfiguration.html
|
||||
[`Segment`]: https://docs.rs/dioxus-router-core/latest/dioxus_router_core/routes/struct.Segment.html
|
||||
[`use_router`]: https://docs.rs/dioxus-router/latest/dioxus_router/hooks/fn.use_router.html
|
||||
[Vue Router]: https://router.vuejs.org/
|
||||
@@ -1,9 +1,5 @@
|
||||
# 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}}
|
||||
```rust, no_run
|
||||
{{#include ../../examples/full_example.rs}}
|
||||
```
|
||||
@@ -1,161 +1,27 @@
|
||||
# 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`].
|
||||
|
||||
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 something that can be converted to 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
|
||||
|
||||
A [`NavigationTarget`] is similar to the `href` of an HTML anchor element. It
|
||||
tells the router where to navigate to. The Dioxus Router knows two kinds of
|
||||
navigation targets:
|
||||
- [`Internal`]: we already saw that. It's basically an `href`, but cannot
|
||||
link to content outside our app.
|
||||
- [`External`]: 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.
|
||||
- [`Named`]: this is the most interesting form of navigation target. We'll look
|
||||
at it in detail in this chapter.
|
||||
|
||||
- [`Internal`]: We used internal links in the previous chapter. It's a link to a page within our
|
||||
app represented as a Route enum.
|
||||
- [`External`]: This works exactly like an HTML anchors' `href`. Don't use this for in-app
|
||||
navigation as it will trigger a page reload by the browser.
|
||||
|
||||
## 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 {
|
||||
render! {
|
||||
Link {
|
||||
target: NavigationTarget::External("https://dioxuslabs.com".into()),
|
||||
"Explicit ExternalTarget target"
|
||||
}
|
||||
Link {
|
||||
target: "https://dioxuslabs.com", // short form
|
||||
"Implicit ExternalTarget target"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```rust, no_run
|
||||
{{#include ../../examples/external_link.rs:component}}
|
||||
```
|
||||
|
||||
> Note that we can use a `str`, just like with [`Internal`]s. The router will
|
||||
> convert a `str` to an [`External`] 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.
|
||||
```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!() }
|
||||
# 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.
|
||||
```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 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:
|
||||
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 {
|
||||
render! {
|
||||
nav {
|
||||
ul {
|
||||
li { Link { target: named::<RootIndex>(), "Home" } }
|
||||
li { Link { target: "/blog", "Blog" } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
[`External`]: https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.External
|
||||
[`Internal`]: https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.Internal
|
||||
[`Named`]: https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html#variant.Named
|
||||
[`NavigationTarget`]: https://docs.rs/dioxus-router-core/latest/dioxus_router_core/navigation/enum.NavigationTarget.html
|
||||
[`RootIndex`]: https://docs.rs/dioxus-router-core/latest/dioxus_router_core/prelude/struct.RootIndex.html
|
||||
@@ -1,65 +1,39 @@
|
||||
# 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.
|
||||
In this chapter, we will cover creating redirects
|
||||
|
||||
## Creating Redirects
|
||||
|
||||
## 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`.
|
||||
if they used the path `/myblog` or `/myblog/:name`.
|
||||
|
||||
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!() }
|
||||
# struct PostId;
|
||||
# struct BlogPostName;
|
||||
# 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 {
|
||||
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>()
|
||||
)
|
||||
))
|
||||
.fixed("myblog", "/blog") // this is new
|
||||
.fallback(comp(PageNotFound))
|
||||
}
|
||||
);
|
||||
# unimplemented!()
|
||||
# }
|
||||
Redirects are special attributes in the router enum that accept a route and a closure
|
||||
with the route parameters. The closure should return a route to redirect to.
|
||||
|
||||
Let's add a redirect to our router enum:
|
||||
|
||||
```rust, no_run
|
||||
{{#include ../../examples/full_example.rs:router}}
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
Well done! You've completed the Dioxus Router guide. 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
|
||||
To continue your journey, you attempt a challenge listed below, look at the [router examples](https://github.com/DioxusLabs/dioxus/tree/master/packages/router/examples), or
|
||||
can check out the [API reference](https://docs.rs/dioxus-router/).
|
||||
|
||||
### Challenges
|
||||
- Organize your components into seperate files for better maintainability.
|
||||
|
||||
- Organize your components into separate 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.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# External Navigation Failure
|
||||
@@ -0,0 +1 @@
|
||||
# Navigation Failures
|
||||
@@ -0,0 +1 @@
|
||||
# Named Navigation Failure
|
||||
@@ -0,0 +1 @@
|
||||
# Redirection Limit Failure
|
||||
@@ -0,0 +1 @@
|
||||
# History Buttons
|
||||
@@ -0,0 +1 @@
|
||||
# History Providers
|
||||
@@ -0,0 +1 @@
|
||||
# Adding the Router to Your Application
|
||||
@@ -0,0 +1 @@
|
||||
# External Navigation
|
||||
@@ -0,0 +1 @@
|
||||
# Links & Navigation
|
||||
@@ -0,0 +1 @@
|
||||
# Named Navigation
|
||||
@@ -0,0 +1 @@
|
||||
# Programmatic Navigation
|
||||
@@ -0,0 +1 @@
|
||||
# Outlets
|
||||
@@ -0,0 +1 @@
|
||||
# Query
|
||||
@@ -0,0 +1 @@
|
||||
# Catch All Routes
|
||||
@@ -0,0 +1 @@
|
||||
# Fallback Routes (404 page)
|
||||
@@ -0,0 +1 @@
|
||||
# Defining Routes
|
||||
@@ -0,0 +1 @@
|
||||
# Matching Routes
|
||||
@@ -0,0 +1 @@
|
||||
# Multiple Components & Redirects
|
||||
@@ -0,0 +1 @@
|
||||
# Nested Routes
|
||||
@@ -0,0 +1 @@
|
||||
# Routing Update Callback
|
||||
@@ -0,0 +1 @@
|
||||
# Sitemap Generation
|
||||
@@ -34,7 +34,7 @@ You can override it by setting the `failure_external_navigation` value of the
|
||||
[`RouterConfiguration`]. The external URL will be provided via the
|
||||
[`FailureExternalNavigation`] parameter.
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
|
||||
@@ -14,7 +14,7 @@ forward buttons:
|
||||
> If you want to navigate through the history programmatically, take a look at
|
||||
> [`programmatic navigation`](./navigation/programmatic.md).
|
||||
|
||||
```rust, no_run
|
||||
```rust, no_run, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
@@ -15,7 +15,7 @@ By default the router uses the [`MemoryHistory`]. It might be changed to use
|
||||
|
||||
You can override the default history:
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
@@ -11,7 +11,7 @@ In most cases we want to add the router to the root component of our app. This
|
||||
way, we can ensure that we have access to all its functionality everywhere. We
|
||||
add it by using the [`use_router`] hook
|
||||
|
||||
```rust
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
@@ -15,7 +15,8 @@ the [`Link`] component is more convenient to use, as it automatically sets the
|
||||
`rel` attribute for the link, when the target is external.
|
||||
|
||||
## Code Example
|
||||
```rust
|
||||
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
@@ -9,6 +9,7 @@ like this:
|
||||
```
|
||||
|
||||
However, we cannot do that when using the router for two reasons:
|
||||
|
||||
1. Anchor tags make the browser load a new page from the server. This takes a
|
||||
lot of time, and it is much faster to let the router handle the navigation
|
||||
client-side.
|
||||
@@ -17,7 +18,8 @@ However, we cannot do that when using the router for two reasons:
|
||||
|
||||
To solve these problems, the router provides us with a [`Link`] component we can
|
||||
use like this:
|
||||
```rust,no_run
|
||||
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
@@ -40,6 +42,7 @@ fn SomeComponent(cx: Scope) -> Element {
|
||||
The `target` in the example above is similar to the `href` of a regular anchor
|
||||
element. However, it tells the router more about what kind of navigation it
|
||||
should perform:
|
||||
|
||||
- The example uses [`Internal`]. We give it an arbitrary path that will be
|
||||
merged with the current URL.
|
||||
- [`Named`] allows us to navigate within our app using predefined names.
|
||||
|
||||
@@ -11,6 +11,7 @@ automatically create the actual path to navigate to, even inserting required
|
||||
parameters.
|
||||
|
||||
_Named_ navigation has a few advantages over _path-based_ navigation:
|
||||
|
||||
- Links can be created without knowing the actual path.
|
||||
- It is much easier to find all links to a specific route.
|
||||
- The router knows what links are invalid (and will panic in debug builds).
|
||||
@@ -27,7 +28,8 @@ _Named_ navigation has a few advantages over _path-based_ navigation:
|
||||
> certain conditions. None of these names can be used for app defined routes.
|
||||
|
||||
## Code Example
|
||||
```rust
|
||||
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
use dioxus::prelude::*;
|
||||
@@ -90,11 +92,12 @@ fn App(cx: Scope) -> Element {
|
||||
```
|
||||
|
||||
## Check if a name is present
|
||||
|
||||
You can check if a specific name is present for the current route. This works
|
||||
similar to getting the value of a [parameter route](../routes/parameter.md) and
|
||||
the same restrictions apply.
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
@@ -4,10 +4,11 @@ Sometimes we want our application to navigate to another page without having the
|
||||
user click on a link. This is called programmatic navigation.
|
||||
|
||||
## Acquiring a [`Navigator`]
|
||||
|
||||
To use programmatic navigation, we first have to acquire a [`Navigator`]. For
|
||||
that purpose we can use the [`use_navigate`] hook.
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
use dioxus::prelude::*;
|
||||
@@ -23,7 +24,9 @@ fn Content(cx: Scope) -> Element {
|
||||
```
|
||||
|
||||
## Triggering a Navigation
|
||||
|
||||
We can use the [`Navigator`] to trigger four different kinds of navigation:
|
||||
|
||||
- `push` will navigate to the target. It works like a regular anchor tag.
|
||||
- `replace` works like `push`, except that it replaces the current history entry
|
||||
instead of adding a new one. This means the prior page cannot be restored with
|
||||
@@ -32,7 +35,7 @@ We can use the [`Navigator`] to trigger four different kinds of navigation:
|
||||
- `Go forward` works like the browsers forward button (the opposite of the back
|
||||
button).
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
@@ -64,6 +67,7 @@ You might have noticed that, like [`Link`], the [`Navigator`]s `push` and
|
||||
[`Internal`], [`Named`] and [`External`].
|
||||
|
||||
## External Navigation Targets
|
||||
|
||||
Unlike a [`Link`], the [`Navigator`] cannot rely on the browser (or webview) to
|
||||
handle navigation to external targets via a generated anchor element.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[`Outlet`]s tell the router where to render content. In the following example
|
||||
the active routes content will be rendered within the [`Outlet`].
|
||||
|
||||
```rust
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
@@ -45,24 +45,21 @@ fn App(cx: Scope) -> Element {
|
||||
|
||||
The example above will output the following HTML (line breaks added for
|
||||
readability):
|
||||
|
||||
```html
|
||||
<header>
|
||||
header
|
||||
</header>
|
||||
<h1>
|
||||
Index
|
||||
</h1>
|
||||
<footer>
|
||||
footer
|
||||
</footer>
|
||||
<header>header</header>
|
||||
<h1>Index</h1>
|
||||
<footer>footer</footer>
|
||||
```
|
||||
|
||||
## Nested Outlets
|
||||
|
||||
When using nested routes, we need to provide equally nested [`Outlet`]s.
|
||||
|
||||
> Learn more about [nested routes](./routes/nested.md) in their own chapter.
|
||||
|
||||
## Named Outlets
|
||||
|
||||
When building complex apps, we often need to display multiple pieces of content
|
||||
simultaneously. For example, we might have a sidebar that changes its content in
|
||||
sync with the main part of the page.
|
||||
@@ -74,7 +71,7 @@ tell the router about our content.
|
||||
We then can use a named [`Outlet`] in our output, to tell the router where to
|
||||
put the side content.
|
||||
|
||||
```rust
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
@@ -127,23 +124,21 @@ fn App(cx: Scope) -> Element {
|
||||
|
||||
The example above will output the following HTML (line breaks added for
|
||||
readability):
|
||||
|
||||
```html
|
||||
<main>
|
||||
Main Content
|
||||
</main>
|
||||
<aside>
|
||||
Side Content
|
||||
</aside>
|
||||
<main>Main Content</main>
|
||||
<aside>Side Content</aside>
|
||||
```
|
||||
|
||||
## Outlet depth override
|
||||
|
||||
When nesting [`Outlet`]s, they communicate with each other. This allows the
|
||||
nested [`Outlet`] to render the content of the nested route.
|
||||
|
||||
We can override the detected value. Be careful when doing so, it is incredibly
|
||||
easy to create an unterminated recursion. See below for an example of that.
|
||||
|
||||
```rust
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
@@ -197,17 +192,17 @@ fn App(cx: Scope) -> Element {
|
||||
|
||||
The example above will output the following HTML (line breaks added for
|
||||
readability):
|
||||
|
||||
```html
|
||||
<h2>
|
||||
Nested
|
||||
</h2>
|
||||
<h2>Nested</h2>
|
||||
```
|
||||
|
||||
### Outlet recursion
|
||||
|
||||
This code will create a crash due to an unterminated recursion using
|
||||
[`Outlet`]s.
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
|
||||
@@ -4,11 +4,12 @@ Some apps use the query part of the URL to encode information. The router allows
|
||||
you to easily access the query, as well as set it when navigating.
|
||||
|
||||
## Accessing the query
|
||||
|
||||
The [`use_route`] hook allows us to access the current query in two ways. The
|
||||
returned `struct` contains a `query` field, that contains the query (without the
|
||||
leading `?`).
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
use dioxus::prelude::*;
|
||||
@@ -26,13 +27,15 @@ fn SomeComponent(cx: Scope) -> Element {
|
||||
```
|
||||
|
||||
## Setting the query
|
||||
|
||||
When navigating we can tell the router to change the query. However, the method
|
||||
we use to do this is very different, depending on how we specify our target.
|
||||
|
||||
### [`Internal`] and [`External`]
|
||||
|
||||
When using [`Internal`] or [`External`] we have to append our query manually.
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
@@ -54,10 +57,11 @@ fn SomeComponent(cx: Scope) -> Element {
|
||||
```
|
||||
|
||||
### [`Named`]
|
||||
|
||||
When using [named navigation](./navigation/name.md) we can pass the query via
|
||||
a function.
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
|
||||
@@ -10,6 +10,7 @@ functionality with catch all routes.
|
||||
> 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
|
||||
@@ -23,7 +24,7 @@ will later also define on our route.
|
||||
> The [`use_route`] hook can only be used in components nested within a
|
||||
> component that called [`use_router`].
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
use dioxus::prelude::*;
|
||||
@@ -45,6 +46,7 @@ fn Greeting(cx: Scope) -> Element {
|
||||
```
|
||||
|
||||
## Defining the routes
|
||||
|
||||
Now we can define our route. Unlike a fixed [`Route`], a [`ParameterRoute`]
|
||||
needs two arguments to be created.
|
||||
|
||||
@@ -54,7 +56,7 @@ needs two arguments to be created.
|
||||
> 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
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
@@ -83,6 +85,7 @@ fn App(cx: Scope) -> Element {
|
||||
```
|
||||
|
||||
## 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:
|
||||
@@ -105,11 +108,13 @@ by the path, i.e. `//`.
|
||||
>
|
||||
> 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
|
||||
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
|
||||
@@ -8,10 +8,11 @@ Fallback routes allow us to do that.
|
||||
> path, like web apps running in the browser.
|
||||
|
||||
## A single global fallback
|
||||
|
||||
To catch all cases of invalid paths within our app, we can simply add a fallback
|
||||
route to our root [`Segment`].
|
||||
|
||||
```rust
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
use dioxus::prelude::*;
|
||||
@@ -59,6 +60,7 @@ fn App(cx: Scope) -> Element {
|
||||
```
|
||||
|
||||
## More specific fallback routes
|
||||
|
||||
In some cases we might want to show different fallback content depending on what
|
||||
section of our app the user is in.
|
||||
|
||||
@@ -73,7 +75,7 @@ will then replace the global fallback whenever our [`Segment`] was active.
|
||||
Note the `.clear_fallback(false)` part. If we didn't add this, the fallback
|
||||
content would be rendered inside the `Settings` component.
|
||||
|
||||
```rust
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
@@ -4,10 +4,11 @@ When creating a router we need to pass it a [`Segment`]. It tells the router
|
||||
about all the routes of our app.
|
||||
|
||||
## Example content
|
||||
|
||||
To get a good understanding of how we define routes we first need to prepare
|
||||
some example content, so we can see the routing in action.
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
use dioxus::prelude::*;
|
||||
@@ -28,6 +29,7 @@ fn Other(cx: Scope) -> Element {
|
||||
```
|
||||
|
||||
## Index routes
|
||||
|
||||
The easiest thing to do is to define an index route.
|
||||
|
||||
Index routes act very similar to `index.html` files in most web servers. They
|
||||
@@ -36,7 +38,7 @@ are active, when we don't specify a route.
|
||||
> Note that we wrap our `Index` component with [`comp`]. This is because of
|
||||
> rust type system requirements.
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
@@ -59,6 +61,7 @@ fn App(cx: Scope) -> Element {
|
||||
```
|
||||
|
||||
## Fixed routes
|
||||
|
||||
It is almost as easy to define a fixed route.
|
||||
|
||||
Fixed routes work similar to how web servers treat files. They are active, when
|
||||
@@ -66,7 +69,7 @@ specified in the path. In the example, the path must be `/other`.
|
||||
|
||||
> The path will be URL decoded before checking if it matches our route.
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
@@ -91,7 +94,8 @@ fn App(cx: Scope) -> Element {
|
||||
```
|
||||
|
||||
## Full Code
|
||||
```rust
|
||||
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
@@ -14,10 +14,11 @@ _Matching_ routes make it easy to implement such behavior.
|
||||
> unfit for all other purposes.
|
||||
|
||||
## Code Example
|
||||
|
||||
> Notice that the parameter of a _matching route_ has the same type as a
|
||||
> [_catch all route_](./catch_all.md).
|
||||
|
||||
```rust
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
@@ -112,6 +113,7 @@ fn App(cx: Scope) -> Element {
|
||||
```
|
||||
|
||||
## Matcher
|
||||
|
||||
In the example above, both _matching routes_ use a regular expression to specify
|
||||
when they match. However, _matching routes_ are not limited to those. They
|
||||
accept all types that implement the [`Matcher`] trait.
|
||||
@@ -119,7 +121,7 @@ accept all types that implement the [`Matcher`] trait.
|
||||
For example, you could (but probably shouldn't) implement a matcher, that
|
||||
matches all values with an even number of characters:
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus_router;
|
||||
# use dioxus_router::prelude::*;
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
# Multiple Components & Redirects
|
||||
|
||||
## Multiple Components
|
||||
|
||||
When creating complex apps we sometimes want to have multiple pieces of content
|
||||
side by side. The router allows us to do this. For more details see the section
|
||||
about [named `Outlet`s](../outlets.md#named-outlets).
|
||||
|
||||
## Redirects
|
||||
|
||||
In some cases we may want to redirect our users to another page whenever they
|
||||
open a specific path. We can tell the router to do this when defining our
|
||||
routes.
|
||||
@@ -16,7 +18,7 @@ routes.
|
||||
In the following example we will redirect everybody from `/` and `/start` to
|
||||
`/home`.
|
||||
|
||||
```rust
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
@@ -22,6 +22,7 @@ We might want to map this structure to these paths and components:
|
||||
Nested routes allow us to do this.
|
||||
|
||||
## Route Depth
|
||||
|
||||
With nesting routes, the router manages content on multiple levels. In our
|
||||
example, when the path is `/settings`, there are two levels of content:
|
||||
|
||||
@@ -34,13 +35,14 @@ content of nested routes to actually be rendered, we also need nested
|
||||
[`Outlet`]s.
|
||||
|
||||
## Defining the content components
|
||||
|
||||
We start by creating the components we want the router to render.
|
||||
|
||||
Take a look at the `Settings` component. When it gets rendered by an [`Outlet`],
|
||||
it will render a second [`Outlet`]. Thus the second [`Outlet`] is nested within
|
||||
the first one, and will in turn render our nested content.
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
@@ -74,13 +76,14 @@ fn PrivacySettings(cx: Scope) -> Element {
|
||||
```
|
||||
|
||||
## Defining the root [`Segment`]
|
||||
|
||||
Now we create the [`Segment`] that we will pass to the router.
|
||||
|
||||
Note that we wrap `comp(Settings)` within a [`Route`]. For this exact code that
|
||||
is unnecessary, as this would be done automatically. However, in the next step
|
||||
we'll use a method of [`Route`], so we might as well add this now.
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
@@ -103,6 +106,7 @@ fn App(cx: Scope) -> Element {
|
||||
```
|
||||
|
||||
## Defining the nested [`Segment`]
|
||||
|
||||
In order to create nested routes we need to create a nested [`Segment`]. We then
|
||||
pass it to the [`Route`] on the root segment.
|
||||
|
||||
@@ -110,7 +114,7 @@ pass it to the [`Route`] on the root segment.
|
||||
>
|
||||
> https://router.example/`root_segment`/`first_nested_segment`/`second_nested_segment`/...
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
@@ -143,7 +147,8 @@ fn App(cx: Scope) -> Element {
|
||||
```
|
||||
|
||||
## Full Code
|
||||
```rust
|
||||
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
|
||||
@@ -4,6 +4,7 @@ In some cases we might want to run custom code when the current route changes.
|
||||
For this reason, the [`RouterConfiguration`] exposes an `on_update` field.
|
||||
|
||||
## How does the callback behave?
|
||||
|
||||
The `on_update` is called whenever the current routing information changes. It
|
||||
is called after the router updated its internal state, but before depended
|
||||
components and hooks are updated.
|
||||
@@ -19,7 +20,8 @@ initiated the navigation, was found as a redirect target or returned by the
|
||||
`on_update` itself.
|
||||
|
||||
## Code Example
|
||||
```rust
|
||||
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# extern crate dioxus_router;
|
||||
|
||||
@@ -5,8 +5,10 @@ generating all pages), Dioxus Router provides functions to extract that
|
||||
information from a [`Segment`].
|
||||
|
||||
## Preparing an app
|
||||
|
||||
We will start by preparing an app with some routes like we normally would.
|
||||
```rust
|
||||
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
use dioxus::prelude::*;
|
||||
@@ -74,10 +76,11 @@ fn App(cx: Scope) -> Element {
|
||||
```
|
||||
|
||||
## Modifying the app to make using sitemaps easier
|
||||
|
||||
Preparing our app for sitemap generation is quite easy. We just need to extract
|
||||
our segment definition into its own function.
|
||||
|
||||
```rust,no_run
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
@@ -117,13 +120,14 @@ fn prepare_routes() -> Segment<Component> {
|
||||
```
|
||||
|
||||
## Sitemaps with parameter names
|
||||
|
||||
The first variant to generate sitemaps is very simple. It finds all routes
|
||||
within the [`Segment`] and adds them to the returned `Vec`.
|
||||
|
||||
Matching and parameter routes are represented by their `key`, prefixed with `\`.
|
||||
Besides that `\`, all paths are URL encoded.
|
||||
|
||||
```rust
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
# extern crate dioxus;
|
||||
# use dioxus::prelude::*;
|
||||
@@ -161,6 +165,7 @@ assert_eq!(sitemap, expected);
|
||||
```
|
||||
|
||||
## Sitemaps with actual parameter values
|
||||
|
||||
The second variant to generate sitemaps is a bit more involved. When it
|
||||
encounters a parameter route, it inserts all values with a matching `key` that
|
||||
were provided to it.
|
||||
@@ -169,7 +174,7 @@ Matching routes only add their path if the value matches their regex.
|
||||
|
||||
All paths are URL encoded.
|
||||
|
||||
```rust
|
||||
```rust, no_run
|
||||
# // Hidden lines (like this one) make the documentation tests work.
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
# extern crate dioxus;
|
||||
|
||||
Reference in new issue
Block a user