fix subscriptions in events

This commit is contained in:
Evan Almloff committed 2023-08-04 17:23:57 -07:00
1 parent 07ed3e67dd
commit a6f611eccf
12 files changed
+445 -103

No files matched your search

+1 -1
View File
@@ -163,7 +163,7 @@ impl VirtualDom {
let listener = unsafe { &*listener };
match &listener.value {
AttributeValue::Listener(l) => {
_ = l.take();
_ = l.callback.take();
}
AttributeValue::Any(a) => {
_ = a.take();
+5 -1
View File
@@ -1,7 +1,9 @@
use std::{
cell::{Cell, RefCell},
rc::Rc,
};
use crate::ScopeId;
/// A wrapper around some generic data that handles the event's state
///
@@ -134,13 +136,15 @@ impl<T: std::fmt::Debug> std::fmt::Debug for Event<T> {
/// }
///
/// ```
pub struct EventHandler<'bump, T = ()> {
pub struct EventHandler<'bump, T:?Sized = ()> {
pub(crate) origin: ScopeId,
pub(super) callback: RefCell<Option<ExternalListenerCallback<'bump, T>>>,
}
impl<T> Default for EventHandler<'_, T> {
fn default() -> Self {
Self {
origin: ScopeId(0),
callback: Default::default(),
}
}
+2 -4
View File
@@ -1,4 +1,4 @@
use crate::{
use crate::prelude::EventHandler;use crate::{
any_props::AnyProps, arena::ElementId, Element, Event, LazyNodes, ScopeId, ScopeState,
};
use bumpalo::boxed::Box as BumpBox;
@@ -476,7 +476,7 @@ pub enum AttributeValue<'a> {
Bool(bool),
/// A listener, like "onclick"
Listener(RefCell<Option<ListenerCb<'a>>>),
Listener(EventHandler<'a, Event<dyn Any>>),
/// An arbitrary value that implements PartialEq and is static
Any(RefCell<Option<BumpBox<'a, dyn AnyValue>>>),
@@ -485,8 +485,6 @@ pub enum AttributeValue<'a> {
None,
}
pub type ListenerCb<'a> = BumpBox<'a, dyn FnMut(Event<dyn Any>) + 'a>;
/// Any of the built-in values that the Dioxus VirtualDom supports as dynamic attributes on elements that are borrowed
///
/// These varients are used to communicate what the value of an attribute is that needs to be updated
+10 -16
View File
@@ -446,7 +446,7 @@ impl<'src> ScopeState {
let handler: &mut dyn FnMut(T) = self.bump().alloc(f);
let caller = unsafe { BumpBox::from_raw(handler as *mut dyn FnMut(T)) };
let callback = RefCell::new(Some(caller));
EventHandler { callback }
EventHandler { callback, origin: self.context().id }
}
/// Create a new [`AttributeValue`] with the listener variant from a callback
@@ -456,22 +456,16 @@ impl<'src> ScopeState {
&'src self,
mut callback: impl FnMut(Event<T>) + 'src,
) -> AttributeValue<'src> {
// safety: there's no other way to create a dynamicly-dispatched bump box other than alloc + from-raw
// This is the suggested way to build a bumpbox
//
// In theory, we could just use regular boxes
let boxed: BumpBox<'src, dyn FnMut(_) + 'src> = unsafe {
BumpBox::from_raw(self.bump().alloc(move |event: Event<dyn Any>| {
if let Ok(data) = event.data.downcast::<T>() {
callback(Event {
propagates: event.propagates,
data,
});
}
}))
};
AttributeValue::Listener(RefCell::new(Some(boxed)))
AttributeValue::Listener(self.event_handler(move |event: Event<dyn Any>| {
if let Ok(data) = event.data.downcast::<T>() {
callback(Event {
propagates: event.propagates,
data,
});
}
}))
}
/// Create a new [`AttributeValue`] with a value that implements [`AnyValue`]
+8 -2
View File
@@ -391,9 +391,12 @@ impl VirtualDom {
// We check the bubble state between each call to see if the event has been stopped from bubbling
for listener in listeners.drain(..).rev() {
if let AttributeValue::Listener(listener) = listener {
if let Some(cb) = listener.borrow_mut().as_deref_mut() {
let origin = listener.origin;
self.runtime.scope_stack.borrow_mut().push(origin);
if let Some(cb) = listener.callback.borrow_mut().as_deref_mut() {
cb(uievent.clone());
}
self.runtime.scope_stack.borrow_mut().pop();
if !uievent.propagates.get() {
return;
@@ -422,9 +425,12 @@ impl VirtualDom {
// Only call the listener if this is the exact target element.
if attr.name.trim_start_matches("on") == name && target_path == this_path {
if let AttributeValue::Listener(listener) = &attr.value {
if let Some(cb) = listener.borrow_mut().as_deref_mut() {
let origin = listener.origin;
self.runtime.scope_stack.borrow_mut().push(origin);
if let Some(cb) = listener.callback.borrow_mut().as_deref_mut() {
cb(uievent.clone());
}
self.runtime.scope_stack.borrow_mut().pop();
break;
}