From c439b0ac7e09f70a04262b7c29938d8c52197b76 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Fri, 7 Jan 2022 11:51:25 -0500 Subject: [PATCH 1/2] fix: component pass thru events --- examples/framework_benchmark.rs | 16 ++++++------ examples/pattern_model.rs | 6 ++--- packages/core-macro/src/rsx/component.rs | 2 +- packages/core/src/nodes.rs | 33 ++++++++++++++++-------- packages/core/src/scopes.rs | 4 +-- packages/hooks/src/useref.rs | 2 +- packages/html/src/events.rs | 5 +--- 7 files changed, 37 insertions(+), 31 deletions(-) diff --git a/examples/framework_benchmark.rs b/examples/framework_benchmark.rs index 2f4496d86..8ed60986a 100644 --- a/examples/framework_benchmark.rs +++ b/examples/framework_benchmark.rs @@ -41,22 +41,22 @@ fn app(cx: Scope) -> Element { div { class: "col-md-6", div { class: "row", ActionButton { name: "Create 1,000 rows", id: "run", - onclick: move || items.set(Label::new_list(1_000)), + onclick: move |_| items.set(Label::new_list(1_000)), } ActionButton { name: "Create 10,000 rows", id: "runlots", - onclick: move || items.set(Label::new_list(10_000)), + onclick: move |_| items.set(Label::new_list(10_000)), } ActionButton { name: "Append 1,000 rows", id: "add", - onclick: move || items.write().extend(Label::new_list(1_000)), + onclick: move |_| items.write().extend(Label::new_list(1_000)), } ActionButton { name: "Update every 10th row", id: "update", - onclick: move || items.write().iter_mut().step_by(10).for_each(|item| item.labels[2] = "!!!"), + onclick: move |_| items.write().iter_mut().step_by(10).for_each(|item| item.labels[2] = "!!!"), } ActionButton { name: "Clear", id: "clear", - onclick: move || items.write().clear(), + onclick: move |_| items.write().clear(), } ActionButton { name: "Swap rows", id: "swaprows", - onclick: move || items.write().swap(0, 998), + onclick: move |_| items.write().swap(0, 998), } } } @@ -91,7 +91,7 @@ fn app(cx: Scope) -> Element { struct ActionButtonProps<'a> { name: &'a str, id: &'a str, - onclick: &'a dyn Fn(), + onclick: EventHandler<'a, ()>, } fn ActionButton<'a>(cx: Scope<'a, ActionButtonProps<'a>>) -> Element { @@ -102,7 +102,7 @@ fn ActionButton<'a>(cx: Scope<'a, ActionButtonProps<'a>>) -> Element { class:"btn btn-primary btn-block", r#type: "button", id: "{cx.props.id}", - onclick: move |_| (cx.props.onclick)(), + onclick: move |_| cx.props.onclick.call(()), "{cx.props.name}" } diff --git a/examples/pattern_model.rs b/examples/pattern_model.rs index 550879c21..c679d1427 100644 --- a/examples/pattern_model.rs +++ b/examples/pattern_model.rs @@ -15,8 +15,6 @@ //! the RefCell will panic and crash. You can use `try_get_mut` or `.modify` to avoid this problem, or just not hold two //! RefMuts at the same time. -use std::sync::Arc; - use dioxus::desktop::wry::application::dpi::LogicalSize; use dioxus::events::*; use dioxus::prelude::*; @@ -117,7 +115,7 @@ fn app(cx: Scope) -> Element { #[derive(Props)] struct CalculatorKeyProps<'a> { name: &'a str, - onclick: &'a dyn Fn(MouseEvent), + onclick: EventHandler<'a, MouseEvent>, children: Element<'a>, } @@ -125,7 +123,7 @@ fn CalculatorKey<'a>(cx: Scope<'a, CalculatorKeyProps<'a>>) -> Element { cx.render(rsx! { button { class: "calculator-key {cx.props.name}", - onclick: move |e| (cx.props.onclick)(e), + onclick: move |e| cx.props.onclick.call(e), &cx.props.children } }) diff --git a/packages/core-macro/src/rsx/component.rs b/packages/core-macro/src/rsx/component.rs index 08dc39580..13bcd30d3 100644 --- a/packages/core-macro/src/rsx/component.rs +++ b/packages/core-macro/src/rsx/component.rs @@ -165,7 +165,7 @@ impl ToTokens for ContentField { __cx.raw_text(format_args_f!(#s)).0 }), ContentField::OnHandlerRaw(e) => tokens.append_all(quote! { - __cx.bump().alloc(#e) + __cx.event_handler(#e) }), } } diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index ed4a6b0df..9917d4094 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -316,29 +316,33 @@ pub struct Listener<'bump> { pub event: &'static str, /// The actual callback that the user specified - pub(crate) callback: EventHandler<'bump>, + pub(crate) callback: InternalHandler<'bump>, } -/// The callback based into element event listeners. -pub struct EventHandler<'bump> { - pub callback: &'bump RefCell>>, +pub type InternalHandler<'bump> = &'bump RefCell>>; +type InternalListenerCallback<'bump> = BumpBox<'bump, dyn FnMut(AnyEvent) + 'bump>; + +type ExternalListenerCallback<'bump, T> = BumpBox<'bump, dyn FnMut(T) + 'bump>; + +/// The callback based through the `rsx!` macro. +pub struct EventHandler<'bump, T = ()> { + pub callback: &'bump RefCell>>, } -impl EventHandler<'_> { - pub fn call(&self, event: AnyEvent) { +impl EventHandler<'_, T> { + pub fn call(&self, event: T) { if let Some(callback) = self.callback.borrow_mut().as_mut() { callback(event); } } + pub fn release(&self) { self.callback.replace(None); } } -type ListenerCallback<'bump> = BumpBox<'bump, dyn FnMut(AnyEvent) + 'bump>; - -impl Copy for EventHandler<'_> {} -impl Clone for EventHandler<'_> { +impl Copy for EventHandler<'_, T> {} +impl Clone for EventHandler<'_, T> { fn clone(&self) -> Self { Self { callback: self.callback, @@ -551,7 +555,7 @@ impl<'a> NodeFactory<'a> { VNode::Component(vcomp) } - pub fn listener(self, event: &'static str, callback: EventHandler<'a>) -> Listener<'a> { + pub fn listener(self, event: &'static str, callback: InternalHandler<'a>) -> Listener<'a> { Listener { event, mounted_node: Cell::new(None), @@ -643,6 +647,13 @@ impl<'a> NodeFactory<'a> { }))) } } + + pub fn event_handler(self, f: impl FnMut(T) + 'a) -> EventHandler<'a, T> { + let handler: &mut dyn FnMut(T) = self.bump.alloc(f); + let caller = unsafe { BumpBox::from_raw(handler as *mut dyn FnMut(T)) }; + let callback = self.bump.alloc(RefCell::new(Some(caller))); + EventHandler { callback } + } } impl Debug for NodeFactory<'_> { diff --git a/packages/core/src/scopes.rs b/packages/core/src/scopes.rs index 1ed715208..bd4dc34ff 100644 --- a/packages/core/src/scopes.rs +++ b/packages/core/src/scopes.rs @@ -212,7 +212,7 @@ impl ScopeArena { items .listeners .drain(..) - .for_each(|listener| drop(listener.callback.callback.borrow_mut().take())); + .for_each(|listener| drop(listener.callback.borrow_mut().take())); } } @@ -300,7 +300,7 @@ impl ScopeArena { break; } - let mut cb = listener.callback.callback.borrow_mut(); + let mut cb = listener.callback.borrow_mut(); if let Some(cb) = cb.as_mut() { // todo: arcs are pretty heavy to clone // we really want to convert arc to rc diff --git a/packages/hooks/src/useref.rs b/packages/hooks/src/useref.rs index 06eb4626c..9a5d9ffb9 100644 --- a/packages/hooks/src/useref.rs +++ b/packages/hooks/src/useref.rs @@ -1,5 +1,5 @@ use std::{ - cell::{Cell, Ref, RefCell, RefMut}, + cell::{Ref, RefCell, RefMut}, rc::Rc, }; diff --git a/packages/html/src/events.rs b/packages/html/src/events.rs index 6338b30e6..7e5e95372 100644 --- a/packages/html/src/events.rs +++ b/packages/html/src/events.rs @@ -43,10 +43,7 @@ pub mod on { // ie copy let shortname: &'static str = &event_name[2..]; - let handler = EventHandler { - callback: bump.alloc(std::cell::RefCell::new(Some(callback))), - }; - + let handler = bump.alloc(std::cell::RefCell::new(Some(callback))); factory.listener(shortname, handler) } )* From 1c691e899c67f1981bdf0febdb7f2f5560ba4a9c Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Fri, 7 Jan 2022 11:53:19 -0500 Subject: [PATCH 2/2] tweak: example --- examples/framework_benchmark.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/framework_benchmark.rs b/examples/framework_benchmark.rs index 8ed60986a..0a70bd25b 100644 --- a/examples/framework_benchmark.rs +++ b/examples/framework_benchmark.rs @@ -91,7 +91,7 @@ fn app(cx: Scope) -> Element { struct ActionButtonProps<'a> { name: &'a str, id: &'a str, - onclick: EventHandler<'a, ()>, + onclick: EventHandler<'a>, } fn ActionButton<'a>(cx: Scope<'a, ActionButtonProps<'a>>) -> Element {