Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix restarting coroutines #3005

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/popup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fn app() -> Element {
let mut emails_sent = use_signal(|| Vec::new() as Vec<String>);

// Wait for responses to the compose channel, and then push them to the emails_sent signal.
let handle = use_coroutine(|mut rx: UnboundedReceiver<String>| async move {
let handle = use_coroutine(move |mut rx: UnboundedReceiver<String>| async move {
use futures_util::StreamExt;
while let Some(message) = rx.next().await {
emails_sent.write().push(message);
Expand Down
49 changes: 17 additions & 32 deletions packages/hooks/src/use_coroutine.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -69,35 +69,24 @@ use std::future::Future;
/// };
/// ```
#[doc = include_str!("../docs/rules_of_hooks.md")]
pub fn use_coroutine<M, G, F>(init: G) -> Coroutine<M>
pub fn use_coroutine<M, G, F>(mut init: G) -> Coroutine<M>
where
M: 'static,
G: FnOnce(UnboundedReceiver<M>) -> F,
G: FnMut(UnboundedReceiver<M>) -> F + 'static,
F: Future<Output = ()> + '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
Expand All @@ -111,15 +100,14 @@ pub fn use_coroutine_handle<M: 'static>() -> Coroutine<M> {
}

pub struct Coroutine<T: 'static> {
needs_regen: Signal<bool>,
tx: CopyValue<Option<UnboundedSender<T>>>,
task: CopyValue<Option<Task>>,
future: UseFuture,
}

impl<T> Coroutine<T> {
/// Get the underlying task handle
pub fn task(&self) -> Task {
(*self.task.read()).unwrap()
self.future.task()
}

/// Send a message to the coroutine
Expand All @@ -132,11 +120,8 @@ impl<T> Coroutine<T> {
}

/// 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();
}
}

Expand All @@ -151,6 +136,6 @@ impl<T> Clone for Coroutine<T> {

impl<T> PartialEq for Coroutine<T> {
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
}
}
2 changes: 1 addition & 1 deletion packages/hooks/src/use_future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ where
}
}

#[derive(Clone, Copy)]
#[derive(Clone, Copy, PartialEq)]
pub struct UseFuture {
task: CopyValue<Task>,
state: Signal<UseFutureState>,
Expand Down
Loading