yew_hooks/hooks/
use_debounce.rs

1use yew::prelude::*;
2
3use super::{use_timeout, UseTimeoutHandle};
4
5/// State handle for the [`use_debounce`] hook.
6pub struct UseDebounceHandle {
7    inner: UseTimeoutHandle,
8}
9
10impl UseDebounceHandle {
11    /// Run the debounce.
12    pub fn run(&self) {
13        self.inner.reset();
14    }
15
16    /// Cancel the debounce.
17    pub fn cancel(&self) {
18        self.inner.cancel();
19    }
20}
21
22impl Clone for UseDebounceHandle {
23    fn clone(&self) -> Self {
24        Self {
25            inner: self.inner.clone(),
26        }
27    }
28}
29
30/// A hook that delays invoking a function until after wait milliseconds have elapsed
31/// since the last time the debounced function was invoked.
32///
33/// # Example
34///
35/// ```rust
36/// # use web_sys::HtmlInputElement;
37/// # use yew::prelude::*;
38/// #
39/// use yew_hooks::prelude::*;
40///
41/// #[function_component(Debounce)]
42/// fn debounce() -> Html {
43///     let status = use_state(|| "Typing stopped".to_string());
44///     let value = use_state(|| "".to_string());
45///     let debounced_value = use_state(|| "".to_string());
46///     
47///     let debounce = {
48///         let value = value.clone();
49///         let status = status.clone();
50///         let debounced_value = debounced_value.clone();
51///         use_debounce(
52///             move || {
53///                 debounced_value.set((*value).clone());
54///                 status.set("Typing stopped".to_string());
55///             },
56///             2000,
57///         )
58///     };
59///     
60///     let oninput = {
61///         let status = status.clone();
62///         let value = value.clone();
63///         let debounce = debounce.clone();
64///         Callback::from(move |e: InputEvent| {
65///             let input: HtmlInputElement = e.target_unchecked_into();
66///             value.set(input.value());
67///             status.set("Waiting for typing to stop...".to_string());
68///             debounce.run();
69///         })
70///     };
71///     
72///     let onclick = { Callback::from(move |_| debounce.cancel()) };
73///     
74///     html! {
75///         <>
76///             <input type="text" value={(*value).clone()} placeholder="Debounced input" {oninput}/>
77///             <button {onclick}>{ "Cancel debounce" }</button>
78///             <p>{&*status}</p>
79///             <p>
80///                 <b>{ "Value: " }</b> {&*value}
81///             </p>
82///             <p>
83///                 <b>{ "Debounced value: " }</b> {&*debounced_value}
84///             </p>
85///         </>
86///     }
87/// }
88/// ```
89#[hook]
90pub fn use_debounce<Callback>(callback: Callback, millis: u32) -> UseDebounceHandle
91where
92    Callback: FnOnce() + 'static,
93{
94    let inner = use_timeout(callback, millis);
95
96    UseDebounceHandle { inner }
97}