Selaa lähdekoodia

Merge pull request #816 from DioxusLabs/jk/static-async-callbacks

Async event handlers
Jon Kelley 2 vuotta sitten
vanhempi
commit
e2a73127f3

+ 8 - 1
examples/button.rs

@@ -6,6 +6,13 @@ fn main() {
 
 fn app(cx: Scope) -> Element {
     cx.render(rsx! {
-        button { "hello, desktop!" }
+        button {
+            onclick: |_| async move {
+                println!("hello, desktop!");
+                tokio::time::sleep(std::time::Duration::from_secs(1)).await;
+                println!("goodbye, desktop!");
+            },
+            "hello, desktop!"
+        }
     })
 }

+ 21 - 0
packages/core/src/events.rs

@@ -3,6 +3,10 @@ use std::{
     rc::Rc,
 };
 
+use futures_util::Future;
+
+use crate::ScopeState;
+
 /// A wrapper around some generic data that handles the event's state
 ///
 ///
@@ -106,6 +110,23 @@ impl<T: std::fmt::Debug> std::fmt::Debug for Event<T> {
     }
 }
 
+#[doc(hidden)]
+pub trait EventReturn<P>: Sized {
+    fn spawn(self, _cx: &ScopeState) {}
+}
+
+impl EventReturn<()> for () {}
+
+pub struct AsyncMarker;
+impl<T> EventReturn<AsyncMarker> for T
+where
+    T: Future<Output = ()> + 'static,
+{
+    fn spawn(self, cx: &ScopeState) {
+        cx.spawn(self);
+    }
+}
+
 /// The callback type generated by the `rsx!` macro when an `on` field is specified for components.
 ///
 /// This makes it possible to pass `move |evt| {}` style closures into components as property fields.

+ 4 - 4
packages/core/src/lib.rs

@@ -71,10 +71,10 @@ pub(crate) mod innerlude {
 
 pub use crate::innerlude::{
     fc_to_builder, AnyValue, Attribute, AttributeValue, BorrowedAttributeValue, CapturedError,
-    Component, DynamicNode, Element, ElementId, Event, Fragment, IntoDynNode, LazyNodes, Mutation,
-    Mutations, Properties, RenderReturn, Scope, ScopeId, ScopeState, Scoped, SuspenseContext,
-    TaskId, Template, TemplateAttribute, TemplateNode, VComponent, VNode, VPlaceholder, VText,
-    VirtualDom,
+    Component, DynamicNode, Element, ElementId, Event, EventReturn, Fragment, IntoDynNode,
+    LazyNodes, Mutation, Mutations, Properties, RenderReturn, Scope, ScopeId, ScopeState, Scoped,
+    SuspenseContext, TaskId, Template, TemplateAttribute, TemplateNode, VComponent, VNode,
+    VPlaceholder, VText, VirtualDom,
 };
 
 /// The purpose of this module is to alleviate imports of many common types

+ 4 - 3
packages/core/src/scopes.rs

@@ -7,7 +7,7 @@ use crate::{
     innerlude::{ErrorBoundary, Scheduler, SchedulerMsg},
     lazynodes::LazyNodes,
     nodes::{ComponentReturn, IntoAttributeValue, IntoDynNode, RenderReturn},
-    AnyValue, Attribute, AttributeValue, Element, Event, Properties, TaskId,
+    AnyValue, Attribute, AttributeValue, Element, Event, EventReturn, Properties, TaskId,
 };
 use bumpalo::{boxed::Box as BumpBox, Bump};
 use bumpslab::{BumpSlab, Slot};
@@ -581,9 +581,9 @@ impl<'src> ScopeState {
     /// Create a new [`AttributeValue`] with the listener variant from a callback
     ///
     /// The callback must be confined to the lifetime of the ScopeState
-    pub fn listener<T: 'static>(
+    pub fn listener<T: 'static, P, E: EventReturn<P>>(
         &'src self,
-        mut callback: impl FnMut(Event<T>) + 'src,
+        mut callback: impl FnMut(Event<T>) -> E + '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
@@ -596,6 +596,7 @@ impl<'src> ScopeState {
                         propagates: event.propagates,
                         data,
                     })
+                    .spawn(self);
                 }
             }))
         };

+ 1 - 1
packages/html/src/events.rs

@@ -8,7 +8,7 @@ macro_rules! impl_event {
     ) => {
         $(
             $( #[$attr] )*
-            pub fn $name<'a>(_cx: &'a ::dioxus_core::ScopeState, _f: impl FnMut(::dioxus_core::Event<$data>) + 'a) -> ::dioxus_core::Attribute<'a> {
+            pub fn $name<'a, E: ::dioxus_core::EventReturn<T>, T>(_cx: &'a ::dioxus_core::ScopeState, _f: impl FnMut(::dioxus_core::Event<$data>) -> E + 'a) -> ::dioxus_core::Attribute<'a> {
                 ::dioxus_core::Attribute {
                     name: stringify!($name),
                     value: _cx.listener(_f),