diff --git a/packages/router-macro/src/lib.rs b/packages/router-macro/src/lib.rs index 3b5ec85d7..c949cf2f4 100644 --- a/packages/router-macro/src/lib.rs +++ b/packages/router-macro/src/lib.rs @@ -485,7 +485,13 @@ impl RouteEnum { let mut segments = route.split('/'); // skip the first empty segment if s.starts_with('/') { - segments.next(); + let _ = segments.next(); + } + else { + // if this route does not start with a slash, it is not a valid route + return Err(dioxus_router::routable::RouteParseError { + attempted_routes: Vec::new(), + }); } let mut errors = Vec::new(); diff --git a/packages/router-macro/src/route_tree.rs b/packages/router-macro/src/route_tree.rs index d855d435a..399d20e5e 100644 --- a/packages/router-macro/src/route_tree.rs +++ b/packages/router-macro/src/route_tree.rs @@ -367,7 +367,7 @@ impl<'a> RouteTreeSegmentData<'a> { let child_name = &child.ident; quote! { - let mut trailing = String::new(); + let mut trailing = String::from("/"); for seg in segments.clone() { trailing += seg; trailing += "/"; diff --git a/packages/router/src/contexts/router.rs b/packages/router/src/contexts/router.rs index e13d1cc20..5a9a3f0c4 100644 --- a/packages/router/src/contexts/router.rs +++ b/packages/router/src/contexts/router.rs @@ -178,7 +178,7 @@ impl RouterContext { match target { NavigationTarget::Internal(p) => { let mut state = self.state_mut(); - state.history.push(Rc::new(p)) + state.history.push(p) } NavigationTarget::External(e) => return self.external(e), } @@ -195,7 +195,7 @@ impl RouterContext { { let mut state = self.state_mut(); match target { - NavigationTarget::Internal(p) => state.history.replace(Rc::new(p)), + NavigationTarget::Internal(p) => state.history.replace(p), NavigationTarget::External(e) => return self.external(e), } } diff --git a/packages/router/src/history/memory.rs b/packages/router/src/history/memory.rs index 07c1f4379..ba511bb97 100644 --- a/packages/router/src/history/memory.rs +++ b/packages/router/src/history/memory.rs @@ -88,6 +88,10 @@ impl HistoryProvider for MemoryHistory { } fn push(&mut self, new: R) { + // don't push the same route twice + if self.current.to_string() == new.to_string() { + return; + } let old = std::mem::replace(&mut self.current, new); self.history.push(old); self.future.clear(); diff --git a/packages/router/src/history/web.rs b/packages/router/src/history/web.rs index 4a395356f..8b6089b20 100644 --- a/packages/router/src/history/web.rs +++ b/packages/router/src/history/web.rs @@ -1,6 +1,7 @@ use std::sync::{Arc, Mutex}; use gloo::{console::error, events::EventListener, render::AnimationFrame}; + use wasm_bindgen::JsValue; use web_sys::{window, History, ScrollRestoration, Window}; @@ -265,11 +266,18 @@ where } fn push(&mut self, state: R) { + use gloo_utils::format::JsValueSerdeExt; + if JsValue::from_serde(&state) != JsValue::from_serde(&self.current_route()) { + // don't push the same state twice + return; + } + let w = window().expect("access to `window`"); let h = w.history().expect("`window` has access to `history`"); // update the scroll position before pushing the new state update_scroll::(&w, &h); + let path = self.full_path(&state); let state = self.create_state(state); @@ -336,6 +344,11 @@ where } fn push(&mut self, state: R) { + if state.to_string() == self.current_route().to_string() { + // don't push the same state twice + return; + } + let w = window().expect("access to `window`"); let h = w.history().expect("`window` has access to `history`");