Преглед изворни кода

feat: connect an onchange listener

Jonathan Kelley пре 3 година
родитељ
комит
29ed7eb

+ 1 - 1
packages/router/README.md

@@ -5,7 +5,7 @@ DioxusRouter adds React-Router style routing to your Dioxus apps. Works in brows
 ```rust
 fn app() {
     cx.render(rsx! {
-        Routes {
+        Router {
             Route { to: "/", Component {} },
             Route { to: "/blog", Blog {} },
             Route { to: "/blog/:id", BlogPost {} },

+ 12 - 3
packages/router/src/components/router.rs

@@ -11,17 +11,26 @@ use crate::RouterService;
 pub struct RouterProps<'a> {
     children: Element<'a>,
 
-    #[props(default, strip_option)]
-    onchange: Option<&'a dyn Fn(&'a str)>,
+    #[props(default)]
+    onchange: EventHandler<'a, String>,
 }
 
 #[allow(non_snake_case)]
 pub fn Router<'a>(cx: Scope<'a, RouterProps<'a>>) -> Element {
-    cx.use_hook(|_| {
+    let svc = cx.use_hook(|_| {
         let update = cx.schedule_update_any();
         cx.provide_context(RouterService::new(update, cx.scope_id()))
     });
 
+    let any_pending = svc.pending_events.borrow().len() > 0;
+    svc.pending_events.borrow_mut().clear();
+
+    if any_pending {
+        let location = svc.current_location();
+        let path = location.path();
+        cx.props.onchange.call(path.to_string());
+    }
+
     cx.render(rsx!(
         div { &cx.props.children }
     ))

+ 1 - 14
packages/router/src/lib.rs

@@ -8,22 +8,9 @@
 //!
 //! ```rust
 //! fn app(cx: Scope) -> Element {
+//!     
 //! }
-//!
-//!
-//!
-//!
-//!
 //! ```
-//!
-//!
-//!
-//!
-//!
-//!
-//!
-//!
-//!
 
 mod hooks {
     mod use_route;

+ 27 - 11
packages/router/src/service.rs

@@ -9,6 +9,7 @@ use dioxus_core::ScopeId;
 
 pub struct RouterService {
     pub(crate) regen_route: Rc<dyn Fn(ScopeId)>,
+    pub(crate) pending_events: Rc<RefCell<Vec<RouteEvent>>>,
     history: Rc<RefCell<BrowserHistory>>,
     slots: Rc<RefCell<Vec<(ScopeId, String)>>>,
     root_found: Rc<Cell<Option<ScopeId>>>,
@@ -16,6 +17,12 @@ pub struct RouterService {
     listener: HistoryListener,
 }
 
+pub enum RouteEvent {
+    Change,
+    Pop,
+    Push,
+}
+
 enum RouteSlot {
     Routes {
         // the partial route
@@ -36,28 +43,37 @@ impl RouterService {
         let path = location.path();
 
         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));
+
+        let listener = history.listen({
+            let pending_events = pending_events.clone();
+            let regen_route = regen_route.clone();
+            let root_found = root_found.clone();
+            let slots = slots.clone();
+            move || {
+                root_found.set(None);
+                // checking if the route is valid is cheap, so we do it
+                for (slot, root) in slots.borrow_mut().iter().rev() {
+                    log::trace!("regenerating slot {:?} for root '{}'", slot, root);
+                    regen_route(*slot);
+                }
 
-        let _slots = slots.clone();
+                // also regenerate the root
+                regen_route(root_scope);
 
-        let root_found = Rc::new(Cell::new(None));
-        let regen = regen_route.clone();
-        let _root_found = root_found.clone();
-        let listener = history.listen(move || {
-            _root_found.set(None);
-            // checking if the route is valid is cheap, so we do it
-            for (slot, root) in _slots.borrow_mut().iter().rev() {
-                log::trace!("regenerating slot {:?} for root '{}'", slot, root);
-                regen(*slot);
+                pending_events.borrow_mut().push(RouteEvent::Change)
             }
         });
 
         Self {
+            listener,
             root_found,
             history: Rc::new(RefCell::new(history)),
             regen_route,
             slots,
+            pending_events,
             cur_path_params: Rc::new(RefCell::new(HashMap::new())),
-            listener,
         }
     }