From 0b1d12b43a6a018c0e9493676dd3101c1872c643 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 26 Sep 2024 12:26:20 -0500 Subject: [PATCH 1/2] Fix restarting coroutines --- packages/hooks/src/use_coroutine.rs | 49 ++++++++++------------------- packages/hooks/src/use_future.rs | 2 +- 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/packages/hooks/src/use_coroutine.rs b/packages/hooks/src/use_coroutine.rs index 278d242011..b0571efb5c 100644 --- a/packages/hooks/src/use_coroutine.rs +++ b/packages/hooks/src/use_coroutine.rs @@ -1,5 +1,5 @@ -use ::warnings::Warning; -use dioxus_core::prelude::{consume_context, provide_context, spawn, use_hook}; +use crate::{use_context_provider, use_future, UseFuture}; +use dioxus_core::prelude::{consume_context, use_hook}; use dioxus_core::Task; use dioxus_signals::*; pub use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender}; @@ -69,35 +69,24 @@ use std::future::Future; /// }; /// ``` #[doc = include_str!("../docs/rules_of_hooks.md")] -pub fn use_coroutine(init: G) -> Coroutine +pub fn use_coroutine(mut init: G) -> Coroutine where M: 'static, - G: FnOnce(UnboundedReceiver) -> F, + G: FnMut(UnboundedReceiver) -> F + 'static, F: Future + 'static, { - let mut coroutine = use_hook(|| { - provide_context(Coroutine { - needs_regen: Signal::new(true), - tx: CopyValue::new(None), - task: CopyValue::new(None), - }) - }); + let mut tx_copy_value = use_hook(|| CopyValue::new(None)); - // We do this here so we can capture data with FnOnce - // this might not be the best API - dioxus_signals::warnings::signal_read_and_write_in_reactive_scope::allow(|| { - dioxus_signals::warnings::signal_write_in_component_body::allow(|| { - if *coroutine.needs_regen.peek() { - let (tx, rx) = futures_channel::mpsc::unbounded(); - let task = spawn(init(rx)); - coroutine.tx.set(Some(tx)); - coroutine.task.set(Some(task)); - coroutine.needs_regen.set(false); - } - }) + let future = use_future(move || { + let (tx, rx) = futures_channel::mpsc::unbounded(); + tx_copy_value.set(Some(tx)); + init(rx) }); - coroutine + use_context_provider(|| Coroutine { + tx: tx_copy_value, + future, + }) } /// Get a handle to a coroutine higher in the tree @@ -111,15 +100,14 @@ pub fn use_coroutine_handle() -> Coroutine { } pub struct Coroutine { - needs_regen: Signal, tx: CopyValue>>, - task: CopyValue>, + future: UseFuture, } impl Coroutine { /// Get the underlying task handle pub fn task(&self) -> Task { - (*self.task.read()).unwrap() + self.future.task() } /// Send a message to the coroutine @@ -132,11 +120,8 @@ impl Coroutine { } /// Restart this coroutine - /// - /// Forces the component to re-render, which will re-invoke the coroutine. pub fn restart(&mut self) { - self.needs_regen.set(true); - self.task().cancel(); + self.future.restart(); } } @@ -151,6 +136,6 @@ impl Clone for Coroutine { impl PartialEq for Coroutine { fn eq(&self, other: &Self) -> bool { - self.needs_regen == other.needs_regen && self.tx == other.tx && self.task == other.task + self.tx == other.tx && self.future == other.future } } diff --git a/packages/hooks/src/use_future.rs b/packages/hooks/src/use_future.rs index d4d41de38a..5bf314b536 100644 --- a/packages/hooks/src/use_future.rs +++ b/packages/hooks/src/use_future.rs @@ -78,7 +78,7 @@ where } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq)] pub struct UseFuture { task: CopyValue, state: Signal, From 8fe7e9398ce42be9257cc844a28e9bee75c49771 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 26 Sep 2024 16:24:50 -0500 Subject: [PATCH 2/2] Fix popup example --- examples/popup.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/popup.rs b/examples/popup.rs index 131d536edb..2c79e0ba75 100644 --- a/examples/popup.rs +++ b/examples/popup.rs @@ -12,7 +12,7 @@ fn app() -> Element { let mut emails_sent = use_signal(|| Vec::new() as Vec); // Wait for responses to the compose channel, and then push them to the emails_sent signal. - let handle = use_coroutine(|mut rx: UnboundedReceiver| async move { + let handle = use_coroutine(move |mut rx: UnboundedReceiver| async move { use futures_util::StreamExt; while let Some(message) = rx.next().await { emails_sent.write().push(message);