dioxus_time/debounce.rs
1use crate::{TimeoutHandle, UseTimeout, use_timeout};
2use dioxus::{
3 dioxus_core::SpawnIfAsync,
4 hooks::use_signal,
5 signals::{Signal, Writable},
6};
7use std::time::Duration;
8
9/// The interface for calling a debounce.
10///
11/// See [`use_debounce`] for more information.
12#[derive(Clone, Copy, PartialEq)]
13pub struct UseDebounce<Args: 'static> {
14 current_handle: Signal<Option<TimeoutHandle>>,
15 timeout: UseTimeout<Args>,
16}
17
18impl<Args> UseDebounce<Args> {
19 /// Start the debounce countdown, resetting it if already started.
20 pub fn action(&mut self, args: Args) {
21 self.cancel();
22 self.current_handle.set(Some(self.timeout.action(args)));
23 }
24
25 /// Cancel the debounce action.
26 pub fn cancel(&mut self) {
27 if let Some(handle) = self.current_handle.take() {
28 handle.cancel();
29 }
30 }
31}
32
33/// A hook for allowing a function to be called only after a provided [`Duration`] has passed.
34///
35/// Once the [`UseDebounce::action`] method is called, a timer will start counting down until
36/// the callback is ran. If the [`UseDebounce::action`] method is called again, the timer will restart.
37///
38/// # Examples
39///
40/// Example of using a debounce:
41/// ```rust
42/// use dioxus::prelude::*;
43/// use dioxus_time::use_debounce;
44/// use std::time::Duration;
45///
46/// #[component]
47/// fn App() -> Element {
48/// // Create a two second debounce.
49/// // This will print "ran" after two seconds since the last action call.
50/// let mut debounce = use_debounce(Duration::from_secs(2), |_| println!("ran"));
51///
52/// rsx! {
53/// button {
54/// onclick: move |_| {
55/// // Call the debounce.
56/// debounce.action(());
57/// },
58/// "Click!"
59/// }
60/// }
61/// }
62/// ```
63///
64/// #### Cancelling A Debounce
65/// If you need to cancel the currently active debounce, you can call [`UseDebounce::cancel`]:
66/// ```rust
67/// use dioxus::prelude::*;
68/// use dioxus_time::use_debounce;
69/// use std::time::Duration;
70///
71/// #[component]
72/// fn App() -> Element {
73/// let mut debounce = use_debounce(Duration::from_secs(5), |_| println!("ran"));
74///
75/// rsx! {
76/// button {
77/// // Start the debounce on click.
78/// onclick: move |_| debounce.action(()),
79/// "Action!"
80/// }
81/// button {
82/// // Cancel the debounce on click.
83/// onclick: move |_| debounce.cancel(),
84/// "Cancel!"
85/// }
86/// }
87/// }
88/// ```
89///
90/// ### Async Debounce
91/// Debounces can accept an async callback:
92/// ```rust
93/// use dioxus::prelude::*;
94/// use dioxus_time::use_debounce;
95/// use std::time::Duration;
96///
97/// #[component]
98/// fn App() -> Element {
99/// // Create a two second debounce that uses some async/await.
100/// let mut debounce = use_debounce(Duration::from_secs(2), |_| async {
101/// println!("debounce called!");
102/// tokio::time::sleep(Duration::from_secs(2)).await;
103/// println!("after async");
104/// });
105///
106/// rsx! {
107/// button {
108/// onclick: move |_| {
109/// // Call the debounce.
110/// debounce.action(());
111/// },
112/// "Click!"
113/// }
114/// }
115/// }
116/// ```
117pub fn use_debounce<Args: 'static, MaybeAsync: SpawnIfAsync<Marker>, Marker>(
118 duration: Duration,
119 callback: impl FnMut(Args) -> MaybeAsync + 'static,
120) -> UseDebounce<Args> {
121 let timeout = use_timeout(duration, callback);
122 let current_handle = use_signal(|| None);
123
124 UseDebounce {
125 timeout,
126 current_handle,
127 }
128}