mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-14 00:17:17 +00:00
Merge pull request #168 from DioxusLabs/jk/use_route_subscribes
fix: use_route should subscribe to changes to the route
This commit is contained in:
commit
0d8e9f5ed4
2 changed files with 50 additions and 8 deletions
|
@ -1,4 +1,4 @@
|
|||
use dioxus_core::ScopeState;
|
||||
use dioxus_core::{ScopeId, ScopeState};
|
||||
use gloo::history::{HistoryResult, Location};
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::{rc::Rc, str::FromStr};
|
||||
|
@ -8,6 +8,7 @@ use crate::RouterService;
|
|||
/// This struct provides is a wrapper around the internal router
|
||||
/// implementation, with methods for getting information about the current
|
||||
/// route.
|
||||
#[derive(Clone)]
|
||||
pub struct UseRoute {
|
||||
router: Rc<RouterService>,
|
||||
}
|
||||
|
@ -74,10 +75,32 @@ impl UseRoute {
|
|||
/// 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
|
||||
.consume_context::<RouterService>()
|
||||
.expect("Cannot call use_route outside the scope of a Router component")
|
||||
.clone();
|
||||
UseRoute { router }
|
||||
pub fn use_route(cx: &ScopeState) -> &UseRoute {
|
||||
&cx.use_hook(|_| {
|
||||
let router = cx
|
||||
.consume_context::<RouterService>()
|
||||
.expect("Cannot call use_route outside the scope of a Router component");
|
||||
|
||||
router.subscribe_onchange(cx.scope_id());
|
||||
|
||||
UseRouteListener {
|
||||
router: UseRoute { router },
|
||||
scope: cx.scope_id(),
|
||||
}
|
||||
})
|
||||
.router
|
||||
}
|
||||
|
||||
// The entire purpose of this struct is to unubscribe this component when it is unmounted.
|
||||
// The UseRoute can be cloned into async contexts, so we can't rely on its drop to unubscribe.
|
||||
// Instead, we hide the drop implementation on this private type exclusive to the hook,
|
||||
// and reveal our cached version of UseRoute to the component.
|
||||
struct UseRouteListener {
|
||||
router: UseRoute,
|
||||
scope: ScopeId,
|
||||
}
|
||||
impl Drop for UseRouteListener {
|
||||
fn drop(&mut self) {
|
||||
self.router.router.unsubscribe_onchange(self.scope)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use gloo::history::{BrowserHistory, History, HistoryListener, Location};
|
||||
use std::{
|
||||
cell::{Cell, Ref, RefCell},
|
||||
collections::HashMap,
|
||||
collections::{HashMap, HashSet},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
|
@ -12,6 +12,7 @@ pub struct RouterService {
|
|||
pub(crate) pending_events: Rc<RefCell<Vec<RouteEvent>>>,
|
||||
history: Rc<RefCell<BrowserHistory>>,
|
||||
slots: Rc<RefCell<Vec<(ScopeId, String)>>>,
|
||||
onchange_listeners: Rc<RefCell<HashSet<ScopeId>>>,
|
||||
root_found: Rc<Cell<Option<ScopeId>>>,
|
||||
cur_path_params: Rc<RefCell<HashMap<String, String>>>,
|
||||
listener: HistoryListener,
|
||||
|
@ -42,6 +43,7 @@ impl RouterService {
|
|||
let location = history.location();
|
||||
let path = location.path();
|
||||
|
||||
let onchange_listeners = Rc::new(RefCell::new(HashSet::new()));
|
||||
let slots: Rc<RefCell<Vec<(ScopeId, String)>>> = Default::default();
|
||||
let pending_events: Rc<RefCell<Vec<RouteEvent>>> = Default::default();
|
||||
let root_found = Rc::new(Cell::new(None));
|
||||
|
@ -51,6 +53,7 @@ impl RouterService {
|
|||
let regen_route = regen_route.clone();
|
||||
let root_found = root_found.clone();
|
||||
let slots = slots.clone();
|
||||
let onchange_listeners = onchange_listeners.clone();
|
||||
move || {
|
||||
root_found.set(None);
|
||||
// checking if the route is valid is cheap, so we do it
|
||||
|
@ -59,6 +62,11 @@ impl RouterService {
|
|||
regen_route(*slot);
|
||||
}
|
||||
|
||||
for listener in onchange_listeners.borrow_mut().iter() {
|
||||
log::trace!("regenerating listener {:?}", listener);
|
||||
regen_route(*listener);
|
||||
}
|
||||
|
||||
// also regenerate the root
|
||||
regen_route(root_scope);
|
||||
|
||||
|
@ -73,6 +81,7 @@ impl RouterService {
|
|||
regen_route,
|
||||
slots,
|
||||
pending_events,
|
||||
onchange_listeners,
|
||||
cur_path_params: Rc::new(RefCell::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
|
@ -143,6 +152,16 @@ impl RouterService {
|
|||
pub fn current_path_params(&self) -> Ref<HashMap<String, String>> {
|
||||
self.cur_path_params.borrow()
|
||||
}
|
||||
|
||||
pub fn subscribe_onchange(&self, id: ScopeId) {
|
||||
log::trace!("Subscribing onchange for scope id {:?}", id);
|
||||
self.onchange_listeners.borrow_mut().insert(id);
|
||||
}
|
||||
|
||||
pub fn unsubscribe_onchange(&self, id: ScopeId) {
|
||||
log::trace!("Subscribing onchange for scope id {:?}", id);
|
||||
self.onchange_listeners.borrow_mut().remove(&id);
|
||||
}
|
||||
}
|
||||
|
||||
fn clean_route(route: String) -> String {
|
||||
|
|
Loading…
Reference in a new issue