Implement UseRoute segment method

This relies on the RouterService to capture path params when it does path
matching.
This commit is contained in:
Dave Rolsky committed 2022-01-13 12:21:06 -06:00
1 parent f8a7e1cd82
commit c9408da731
2 files changed
+30 -18

No files matched your search

+13 -4
View File
@@ -1,6 +1,6 @@
use dioxus_core::ScopeState; use dioxus_core::ScopeState;
use gloo::history::Location; use gloo::history::Location;
use std::rc::Rc; use std::{rc::Rc, str::FromStr};
use crate::RouterService; use crate::RouterService;
@@ -33,9 +33,18 @@ impl<'a> UseRoute<'a> {
Some(segments.remove(len - 1)) Some(segments.remove(len - 1))
} }
/// Parse the segments of the URL, using named parameters (defined in your router) /// Get the named parameter from the path, as defined in your router. The
pub fn segment<T>(&self, name: &str) -> Option<&T> { /// value will be parsed into the type specified by `T` by calling
todo!() /// `value.parse::<T>()`. This method returns `None` if the named
/// parameter does not exist in the current path.
pub fn segment<T>(&self, name: &str) -> Option<Result<T, T::Err>>
where
T: FromStr,
{
self.router
.current_path_params()
.get(name)
.and_then(|v| Some(v.parse::<T>()))
} }
pub fn current_location(&self) -> Location { pub fn current_location(&self) -> Location {
+17 -14
View File
@@ -1,6 +1,7 @@
use gloo::history::{BrowserHistory, History, HistoryListener, Location}; use gloo::history::{BrowserHistory, History, HistoryListener, Location};
use std::{ use std::{
cell::{Cell, RefCell}, cell::{Cell, Ref, RefCell},
collections::HashMap,
rc::Rc, rc::Rc,
}; };
@@ -9,10 +10,9 @@ use dioxus_core::ScopeId;
pub struct RouterService { pub struct RouterService {
pub(crate) regen_route: Rc<dyn Fn(ScopeId)>, pub(crate) regen_route: Rc<dyn Fn(ScopeId)>,
history: Rc<RefCell<BrowserHistory>>, history: Rc<RefCell<BrowserHistory>>,
registered_routes: RefCell<RouteSlot>,
slots: Rc<RefCell<Vec<(ScopeId, String)>>>, slots: Rc<RefCell<Vec<(ScopeId, String)>>>,
root_found: Rc<Cell<bool>>, root_found: Rc<Cell<bool>>,
cur_root: RefCell<String>, cur_path_params: Rc<RefCell<HashMap<String, String>>>,
listener: HistoryListener, listener: HistoryListener,
} }
@@ -52,16 +52,11 @@ impl RouterService {
}); });
Self { Self {
registered_routes: RefCell::new(RouteSlot::Routes {
partial: String::from("/"),
total: String::from("/"),
rest: Vec::new(),
}),
root_found, root_found,
history: Rc::new(RefCell::new(history)), history: Rc::new(RefCell::new(history)),
regen_route, regen_route,
slots, slots,
cur_root: RefCell::new(path.to_string()), cur_path_params: Rc::new(RefCell::new(HashMap::new())),
listener, listener,
} }
} }
@@ -100,9 +95,10 @@ impl RouterService {
scope, scope,
route, route,
); );
if route_matches_path(route, path) { if let Some(params) = route_matches_path(route, path) {
log::trace!(" and it matches the current path '{}'", path); log::trace!(" and it matches the current path '{}'", path);
self.root_found.set(true); self.root_found.set(true);
*self.cur_path_params.borrow_mut() = params;
true true
} else { } else {
if route == "" { if route == "" {
@@ -122,6 +118,10 @@ impl RouterService {
pub fn current_location(&self) -> Location { pub fn current_location(&self) -> Location {
self.history.borrow().location().clone() self.history.borrow().location().clone()
} }
pub fn current_path_params(&self) -> Ref<HashMap<String, String>> {
self.cur_path_params.borrow()
}
} }
fn clean_route(route: String) -> String { fn clean_route(route: String) -> String {
@@ -138,7 +138,7 @@ fn clean_path(path: &str) -> &str {
path.trim_end_matches('/') path.trim_end_matches('/')
} }
fn route_matches_path(route: &str, path: &str) -> bool { fn route_matches_path(route: &str, path: &str) -> Option<HashMap<String, String>> {
let route_pieces = route.split('/').collect::<Vec<_>>(); let route_pieces = route.split('/').collect::<Vec<_>>();
let path_pieces = clean_path(path).split('/').collect::<Vec<_>>(); let path_pieces = clean_path(path).split('/').collect::<Vec<_>>();
@@ -150,9 +150,10 @@ fn route_matches_path(route: &str, path: &str) -> bool {
if route_pieces.len() != path_pieces.len() { if route_pieces.len() != path_pieces.len() {
log::trace!(" the routes are different lengths"); log::trace!(" the routes are different lengths");
return false; return None;
} }
let mut matches = HashMap::new();
for (i, r) in route_pieces.iter().enumerate() { for (i, r) in route_pieces.iter().enumerate() {
log::trace!(" checking route piece '{}' vs path", r); log::trace!(" checking route piece '{}' vs path", r);
// If this is a parameter then it matches as long as there's // If this is a parameter then it matches as long as there's
@@ -162,6 +163,8 @@ fn route_matches_path(route: &str, path: &str) -> bool {
" route piece '{}' starts with a colon so it matches anything", " route piece '{}' starts with a colon so it matches anything",
r, r,
); );
let param = &r[1..];
matches.insert(param.to_string(), path_pieces[i].to_string());
continue; continue;
} }
log::trace!( log::trace!(
@@ -170,11 +173,11 @@ fn route_matches_path(route: &str, path: &str) -> bool {
path_pieces[i], path_pieces[i],
); );
if path_pieces[i] != *r { if path_pieces[i] != *r {
return false; return None;
} }
} }
return true; Some(matches)
} }
pub struct RouterCfg { pub struct RouterCfg {