Skip to content

Commit 7311c39

Browse files
committed
feat: async interval
1 parent 6ce21d2 commit 7311c39

File tree

2 files changed

+81
-21
lines changed

2 files changed

+81
-21
lines changed

examples/timing/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ fn App() -> Element {
1111
let mut count = use_signal(|| 0);
1212

1313
// using `use_interval`, we increment the count by 1 every second.
14-
use_interval(Duration::from_secs(1), move || {
14+
use_interval(Duration::from_secs(1), move |()| {
1515
count += 1;
1616
});
1717

packages/time/src/interval.rs

Lines changed: 80 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
1-
use dioxus::prelude::{use_hook, Callback, Writable};
1+
use dioxus::{
2+
dioxus_core::SpawnIfAsync,
3+
prelude::{spawn, use_hook, Callback, Task, Writable},
4+
signals::Signal,
5+
};
26
use std::time::Duration;
37

48
/// The interface to a debounce.
59
///
6-
/// This handle allows you to cancel an interval.
10+
/// You can cancel an interval with [`UseInterval::cancel`].
11+
/// See [`use_interval`] for more information.
712
#[derive(Clone, PartialEq, Copy)]
813
pub struct UseInterval {
9-
inner: dioxus::prelude::Signal<InnerUseInterval>,
14+
inner: Signal<InnerUseInterval>,
1015
}
1116

1217
struct InnerUseInterval {
13-
pub(crate) interval: Option<dioxus::prelude::Task>,
18+
pub(crate) interval: Option<Task>,
1419
}
1520

1621
impl Drop for InnerUseInterval {
@@ -35,6 +40,50 @@ impl UseInterval {
3540
/// Intervals are cancelable with the [`UseInterval::cancel`] method.
3641
///
3742
/// # Examples
43+
///
44+
/// Example of using an interval:
45+
/// ```rust
46+
/// use dioxus::prelude::*;
47+
/// use dioxus_time::use_interval;
48+
/// use std::time::Duration;
49+
///
50+
/// #[component]
51+
/// fn App() -> Element {
52+
/// let mut time_elapsed = use_signal(|| 0);
53+
/// // Create an interval that increases the time elapsed signal by one every second.
54+
/// use_interval(Duration::from_secs(1), move |()| time_elapsed += 1);
55+
///
56+
/// rsx! {
57+
/// "It has been {time_elapsed} since the app started."
58+
/// }
59+
/// }
60+
/// ```
61+
///
62+
/// #### Cancelling Intervals
63+
/// Example of cancelling an interval:
64+
/// ```rust
65+
/// use dioxus::prelude::*;
66+
/// use dioxus_time::use_interval;
67+
/// use std::time::Duration;
68+
///
69+
/// #[component]
70+
/// fn App() -> Element {
71+
/// let mut time_elapsed = use_signal(|| 0);
72+
/// let mut interval = use_interval(Duration::from_secs(1), move |()| time_elapsed += 1);
73+
///
74+
/// rsx! {
75+
/// "It has been {time_elapsed} since the app started."
76+
/// button {
77+
/// // Cancel the interval when the button is clicked.
78+
/// onclick: move |_| interval.cancel(),
79+
/// "Cancel Interval"
80+
/// }
81+
/// }
82+
/// }
83+
/// ```
84+
///
85+
/// #### Async Intervals
86+
/// Intervals can accept an async callback:
3887
/// ```rust
3988
/// use dioxus::prelude::*;
4089
/// use dioxus_time::use_interval;
@@ -43,34 +92,45 @@ impl UseInterval {
4392
/// #[component]
4493
/// fn App() -> Element {
4594
/// let mut time_elapsed = use_signal(|| 0);
46-
/// use_interval(Duration::from_secs(1), move || *time_elapsed.write() += 1);
95+
/// // Create an interval that increases the time elapsed signal by one every second.
96+
/// use_interval(Duration::from_secs(1), move |()| async move {
97+
/// time_elapsed += 1;
98+
/// // Pretend we're doing some async work.
99+
/// tokio::time::sleep(Duration::from_secs(1)).await;
100+
/// println!("Done!");
101+
/// });
47102
///
48103
/// rsx! {
49104
/// "It has been {time_elapsed} since the app started."
50105
/// }
51106
/// }
52107
/// ```
53-
pub fn use_interval(period: Duration, mut action: impl FnMut() + 'static) -> UseInterval {
108+
pub fn use_interval<MaybeAsync: SpawnIfAsync<Marker>, Marker>(
109+
period: Duration,
110+
callback: impl FnMut(()) -> MaybeAsync + 'static,
111+
) -> UseInterval {
54112
let inner = use_hook(|| {
55-
let callback = Callback::new(move |()| {
56-
action();
57-
});
113+
let callback = Callback::new(callback);
58114

59-
dioxus::prelude::Signal::new(InnerUseInterval {
60-
interval: Some(dioxus::prelude::spawn(async move {
61-
#[cfg(not(target_family = "wasm"))]
62-
let mut interval = tokio::time::interval(period);
115+
let task = spawn(async move {
116+
#[cfg(not(target_family = "wasm"))]
117+
let mut interval = tokio::time::interval(period);
63118

64-
loop {
65-
#[cfg(not(target_family = "wasm"))]
66-
interval.tick().await;
119+
loop {
120+
#[cfg(not(target_family = "wasm"))]
121+
interval.tick().await;
67122

68-
#[cfg(target_family = "wasm")]
123+
#[cfg(target_family = "wasm")]
124+
{
69125
gloo_timers::future::sleep(period).await;
70-
71-
callback.call(());
72126
}
73-
})),
127+
128+
callback.call(());
129+
}
130+
});
131+
132+
Signal::new(InnerUseInterval {
133+
interval: Some(task),
74134
})
75135
});
76136

0 commit comments

Comments
 (0)