From fb75948363fdcc182292431e2c8706d883cc07c1 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Mon, 31 Jan 2022 14:33:25 -0500 Subject: [PATCH 1/2] fix: usestate modify panic --- packages/hooks/src/usestate.rs | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/packages/hooks/src/usestate.rs b/packages/hooks/src/usestate.rs index bce5b2b88..d77d7ceaa 100644 --- a/packages/hooks/src/usestate.rs +++ b/packages/hooks/src/usestate.rs @@ -39,16 +39,17 @@ pub fn use_state<'a, T: 'static>( let setter = Rc::new({ crate::to_owned![update_callback, slot]; move |new| { - let mut slot = slot.borrow_mut(); + { + let mut slot = slot.borrow_mut(); - // if there's only one reference (weak or otherwise), we can just swap the values - // Typically happens when the state is set multiple times - we don't want to create a new Rc for each new value - if let Some(val) = Rc::get_mut(&mut slot) { - *val = new; - } else { - *slot = Rc::new(new); + // if there's only one reference (weak or otherwise), we can just swap the values + // Typically happens when the state is set multiple times - we don't want to create a new Rc for each new value + if let Some(val) = Rc::get_mut(&mut slot) { + *val = new; + } else { + *slot = Rc::new(new); + } } - update_callback(); } }); @@ -92,7 +93,7 @@ impl UseState { /// } /// }) /// } - /// ``` + /// ``` #[must_use] pub fn current(&self) -> Rc { self.slot.borrow().clone() @@ -137,10 +138,10 @@ impl UseState { /// # use dioxus_hooks::*; /// fn component(cx: Scope) -> Element { /// let (value, set_value) = use_state(&cx, || 0); - /// + /// /// // to increment the value /// set_value.modify(|v| v + 1); - /// + /// /// // usage in async /// cx.spawn({ /// let set_value = set_value.to_owned(); @@ -153,8 +154,10 @@ impl UseState { /// } /// ``` pub fn modify(&self, f: impl FnOnce(&T) -> T) { - let current = self.slot.borrow(); - let new_val = f(current.as_ref()); + let new_val = { + let current = self.slot.borrow(); + f(current.as_ref()) + }; (self.setter)(new_val); } @@ -176,7 +179,7 @@ impl UseState { /// # use dioxus_hooks::*; /// fn component(cx: Scope) -> Element { /// let (value, set_value) = use_state(&cx, || 0); - /// + /// /// let as_rc = set_value.get(); /// assert_eq!(as_rc.as_ref(), &0); /// @@ -201,7 +204,7 @@ impl UseState { /// } /// }) /// } - /// ``` + /// ``` pub fn needs_update(&self) { (self.update_callback)(); } From 8badf90a03b1fba883bbca598a685e7d1ce367c2 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Mon, 31 Jan 2022 15:53:06 -0500 Subject: [PATCH 2/2] fix: dioxus web prevents default on in nested targets this commit fixes an issue where we used the event target to prevent default even if the target element wasn't an event handler. --- packages/web/src/dom.rs | 100 +++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 53 deletions(-) diff --git a/packages/web/src/dom.rs b/packages/web/src/dom.rs index ffbef9f4b..733e50e4b 100644 --- a/packages/web/src/dom.rs +++ b/packages/web/src/dom.rs @@ -28,17 +28,54 @@ impl WebsysDom { pub fn new(cfg: WebConfig, sender_callback: Rc) -> Self { // eventually, we just want to let the interpreter do all the work of decoding events into our event type let callback: Box = Box::new(move |event: &web_sys::Event| { - if let Ok(synthetic_event) = decode_trigger(event) { + let mut target = event + .target() + .expect("missing target") + .dyn_into::() + .expect("not a valid element"); + + let typ = event.type_(); + + let decoded: anyhow::Result = loop { + match target.get_attribute("data-dioxus-id").map(|f| f.parse()) { + Some(Ok(id)) => { + break Ok(UserEvent { + name: event_name_from_typ(&typ), + data: virtual_event_from_websys_event(event.clone()), + element: Some(ElementId(id)), + scope_id: None, + priority: dioxus_core::EventPriority::Medium, + }); + } + Some(Err(e)) => { + break Err(e.into()); + } + None => { + // walk the tree upwards until we actually find an event target + if let Some(parent) = target.parent_element() { + target = parent; + } else { + break Ok(UserEvent { + name: event_name_from_typ(&typ), + data: virtual_event_from_websys_event(event.clone()), + element: None, + scope_id: None, + priority: dioxus_core::EventPriority::Low, + }); + } + } + } + }; + + if let Ok(synthetic_event) = decoded { // Try to prevent default if the attribute is set - if let Some(target) = event.target() { - if let Some(node) = target.dyn_ref::() { - if let Some(name) = node.get_attribute("dioxus-prevent-default") { - if name == synthetic_event.name - || name.trim_start_matches("on") == synthetic_event.name - { - log::trace!("Preventing default"); - event.prevent_default(); - } + if let Some(node) = target.dyn_ref::() { + if let Some(name) = node.get_attribute("dioxus-prevent-default") { + if name == synthetic_event.name + || name.trim_start_matches("on") == synthetic_event.name + { + log::trace!("Preventing default"); + event.prevent_default(); } } } @@ -274,49 +311,6 @@ fn virtual_event_from_websys_event(event: web_sys::Event) -> Arc anyhow::Result { - let mut target = event - .target() - .expect("missing target") - .dyn_into::() - .expect("not a valid element"); - - let typ = event.type_(); - - loop { - match target.get_attribute("data-dioxus-id").map(|f| f.parse()) { - Some(Ok(id)) => { - return Ok(UserEvent { - name: event_name_from_typ(&typ), - data: virtual_event_from_websys_event(event.clone()), - element: Some(ElementId(id)), - scope_id: None, - priority: dioxus_core::EventPriority::Medium, - }); - } - Some(Err(e)) => { - return Err(e.into()); - } - None => { - // walk the tree upwards until we actually find an event target - if let Some(parent) = target.parent_element() { - target = parent; - } else { - return Ok(UserEvent { - name: event_name_from_typ(&typ), - data: virtual_event_from_websys_event(event.clone()), - element: None, - scope_id: None, - priority: dioxus_core::EventPriority::Low, - }); - } - } - } - } -} - pub(crate) fn load_document() -> Document { web_sys::window() .expect("should have access to the Window")