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}