More WIP router implementation

This commit is contained in:
Dave Rolsky committed 2022-01-13 12:26:49 -06:00
1 parent c9408da731
commit e06eac1ce5
2 files changed
+40 -18

No files matched your search

+9 -3
View File
@@ -2,6 +2,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus::router::{Link, Route, Router}; use dioxus::router::{Link, Route, Router};
use serde::Deserialize;
fn main() { fn main() {
dioxus::desktop::launch(app); dioxus::desktop::launch(app);
@@ -30,7 +31,7 @@ fn app(cx: Scope) -> Element {
} }
fn BlogPost(cx: Scope) -> Element { fn BlogPost(cx: Scope) -> Element {
let post = dioxus::router::use_route(&cx).last_segment()?; let post = dioxus::router::use_route(&cx).last_segment();
cx.render(rsx! { cx.render(rsx! {
div { div {
@@ -40,9 +41,14 @@ fn BlogPost(cx: Scope) -> Element {
}) })
} }
#[derive(Deserialize)]
struct Query {
bold: bool,
}
fn User(cx: Scope) -> Element { fn User(cx: Scope) -> Element {
let post = dioxus::router::use_route(&cx).last_segment()?; let post = dioxus::router::use_route(&cx).last_segment();
let bold = dioxus::router::use_route(&cx).param::<bool>("bold"); let query = dioxus::router::use_route(&cx).query::<Query>();
cx.render(rsx! { cx.render(rsx! {
div { div {
+31 -15
View File
@@ -1,20 +1,29 @@
use dioxus_core::ScopeState; use dioxus_core::ScopeState;
use gloo::history::Location; use gloo::history::{HistoryResult, Location};
use serde::de::DeserializeOwned;
use std::{rc::Rc, str::FromStr}; use std::{rc::Rc, str::FromStr};
use crate::RouterService; use crate::RouterService;
pub struct UseRoute<'a> { /// This struct provides is a wrapper around the internal router
/// implementation, with methods for getting information about the current
/// route.
pub struct UseRoute {
router: Rc<RouterService>, router: Rc<RouterService>,
cx: &'a ScopeState,
} }
impl<'a> UseRoute<'a> { impl UseRoute {
/// Parse the query part of the URL /// This method simply calls the [`Location::query`] method.
pub fn param<T>(&self, param: &str) -> Option<&T> { pub fn query<T>(&self) -> HistoryResult<T>
todo!() where
T: DeserializeOwned,
{
self.current_location().query::<T>()
} }
/// Returns the nth segment in the path. Paths that end with a slash have
/// the slash removed before determining the segments. If the path has
/// fewer segments than `n` then this method returns `None`.
pub fn nth_segment(&self, n: usize) -> Option<String> { pub fn nth_segment(&self, n: usize) -> Option<String> {
let mut segments = self.path_segments(); let mut segments = self.path_segments();
let len = segments.len(); let len = segments.len();
@@ -24,13 +33,12 @@ impl<'a> UseRoute<'a> {
Some(segments.remove(n)) Some(segments.remove(n))
} }
pub fn last_segment(&self) -> Option<String> { /// Returns the last segment in the path. Paths that end with a slash have
/// the slash removed before determining the segments. The root path, `/`,
/// will return an empty string.
pub fn last_segment(&self) -> String {
let mut segments = self.path_segments(); let mut segments = self.path_segments();
let len = segments.len(); segments.remove(segments.len() - 1)
if len == 0 {
return None;
}
Some(segments.remove(len - 1))
} }
/// Get the named parameter from the path, as defined in your router. The /// Get the named parameter from the path, as defined in your router. The
@@ -47,21 +55,29 @@ impl<'a> UseRoute<'a> {
.and_then(|v| Some(v.parse::<T>())) .and_then(|v| Some(v.parse::<T>()))
} }
/// Returns the [Location] for the current route.
pub fn current_location(&self) -> Location { pub fn current_location(&self) -> Location {
self.router.current_location() self.router.current_location()
} }
fn path_segments(&self) -> Vec<String> { fn path_segments(&self) -> Vec<String> {
let location = self.router.current_location(); let location = self.router.current_location();
let path = location.path();
if path == "/" {
return vec![String::new()];
}
let stripped = &location.path()[1..]; let stripped = &location.path()[1..];
stripped.split('/').map(str::to_string).collect::<Vec<_>>() stripped.split('/').map(str::to_string).collect::<Vec<_>>()
} }
} }
pub fn use_route<'a>(cx: &'a ScopeState) -> UseRoute<'a> { /// This hook provides access to information about the current location in the
/// context of a [`Router`]. If this function is called outside of a `Router`
/// component it will panic.
pub fn use_route(cx: &ScopeState) -> UseRoute {
let router = cx let router = cx
.consume_context::<RouterService>() .consume_context::<RouterService>()
.expect("Cannot call use_route outside the scope of a Router component") .expect("Cannot call use_route outside the scope of a Router component")
.clone(); .clone();
UseRoute { router, cx } UseRoute { router }
} }