Files
dioxus/docs/router/src/features/outlets.md
T

248 lines
5.7 KiB
Markdown

# Outlets
[`Outlet`]s tell the router where to render content. In the following example
the active routes content will be rendered within the [`Outlet`].
```rust
# // Hidden lines (like this one) make the documentation tests work.
# extern crate dioxus;
# use dioxus::prelude::*;
# extern crate dioxus_router;
# use dioxus_router::prelude::*;
# extern crate dioxus_ssr;
fn Index(cx: Scope) -> Element {
render! {
h1 { "Index" }
}
}
fn App(cx: Scope) -> Element {
use_router(
cx,
&|| RouterConfiguration {
# synchronous: true,
..Default::default()
},
&|| Segment::content(comp(Index))
);
render! {
header { "header" }
Outlet { }
footer { "footer" }
}
}
#
# let mut vdom = VirtualDom::new(App);
# vdom.rebuild();
# let html = dioxus_ssr::render(&vdom);
# assert_eq!(
# html,
# "<header>header</header><h1>Index</h1><footer>footer</footer>"
# );
```
The example above will output the following HTML (line breaks added for
readability):
```html
<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.
When defining our routes, we can use `RouteContentMulti` instead of
`RouteContent::Component` (we've been using this through the `Into` trait) to
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
# // Hidden lines (like this one) make the documentation tests work.
# extern crate dioxus;
# use dioxus::prelude::*;
# extern crate dioxus_router;
# use dioxus_router::prelude::*;
# extern crate dioxus_ssr;
#
fn Main(cx: Scope) -> Element {
render! {
main { "Main Content" }
}
}
struct AsideName;
fn Aside(cx: Scope) -> Element {
render! {
aside { "Side Content" }
}
}
fn App(cx: Scope) -> Element {
use_router(
cx,
&|| RouterConfiguration {
# synchronous: true,
..Default::default()
},
&|| {
Segment::content(
multi(Some(comp(Main)))
.add_named::<AsideName>(comp(Aside))
)
}
);
render! {
Outlet { }
Outlet {
name: Name::of::<AsideName>()
}
}
}
#
# let mut vdom = VirtualDom::new(App);
# vdom.rebuild();
# let html = dioxus_ssr::render(&vdom);
# assert_eq!(html, "<main>Main Content</main><aside>Side Content</aside>");
```
The example above will output the following HTML (line breaks added for
readability):
```html
<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
# // 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;
#
fn RootContent(cx: Scope) -> Element {
render! {
h1 { "Root" }
Outlet { }
}
}
fn NestedContent(cx: Scope) -> Element {
render! {
h2 { "Nested" }
}
}
fn App(cx: Scope) -> Element {
use_router(
cx,
&|| RouterConfiguration {
# synchronous: true,
# history: Box::new(MemoryHistory::with_initial_path("/root").unwrap()),
..Default::default()
},
&|| {
Segment::empty().fixed(
"root",
Route::content(comp(RootContent)).nested(
Segment::content(comp(NestedContent))
)
)
}
);
render! {
Outlet {
depth: 1
}
}
}
#
# let mut vdom = VirtualDom::new(App);
# vdom.rebuild();
# let html = dioxus_ssr::render(&vdom);
# assert_eq!(html, "<h2>Nested</h2>");
```
The example above will output the following HTML (line breaks added for
readability):
```html
<h2>
Nested
</h2>
```
### Outlet recursion
This code will create a crash due to an unterminated recursion using
[`Outlet`]s.
```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 Content(cx: Scope) -> Element {
render! {
h1 { "Heyho!" }
Outlet {
depth: 0,
}
}
}
fn App(cx: Scope) -> Element {
use_router(cx, &Default::default, &|| Segment::content(comp(Content)));
render! {
Outlet { }
}
}
```
The [`Outlet`] in the `App` component has no parent [`Outlet`], so its depth
will be `0`. When rendering for the path `/`, it therefore will render the
`Content` component.
The `Content` component will render an `h1` and an [`Outlet`]. That [`OUtlet`]
would usually have a depth of `1`, since it is a descendant of the [`Outlet`] in
the `App` component. However, we override its depth to `0`, so it will render
the `Content` component.
That means the `Content` component will recurse until someone (e.g. the OS) puts
a stop to it.
[`Outlet`]: https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Outlet.html