yew_hooks/hooks/
use_debounce_state.rs

1use std::ops::Deref;
2use std::rc::Rc;
3
4use yew::prelude::*;
5
6use super::use_debounce;
7
8/// State handle for the [`use_debounce_state`] hook.
9pub struct UseDebounceStateHandle<T> {
10    inner: UseStateHandle<T>,
11    set: Rc<dyn Fn(T)>,
12}
13
14impl<T> UseDebounceStateHandle<T> {
15    // Set the value.
16    pub fn set(&self, value: T) {
17        (self.set)(value);
18    }
19}
20
21impl<T> Deref for UseDebounceStateHandle<T> {
22    type Target = T;
23
24    fn deref(&self) -> &Self::Target {
25        &self.inner
26    }
27}
28
29impl<T> Clone for UseDebounceStateHandle<T> {
30    fn clone(&self) -> Self {
31        Self {
32            inner: self.inner.clone(),
33            set: self.set.clone(),
34        }
35    }
36}
37
38impl<T> PartialEq for UseDebounceStateHandle<T>
39where
40    T: PartialEq,
41{
42    fn eq(&self, other: &Self) -> bool {
43        *self.inner == *other.inner
44    }
45}
46
47/// A hook that delays updating state until after wait milliseconds have elapsed
48/// since the last time state was updated.
49///
50/// # Example
51///
52/// ```rust
53/// # use web_sys::HtmlInputElement;
54/// # use yew::prelude::*;
55/// #
56/// use yew_hooks::prelude::*;
57///
58/// #[function_component(DebounceState)]
59/// fn debounce_state() -> Html {
60///     let state = use_debounce_state(|| "".to_string(), 2000);
61///
62///     let oninput = {
63///         let state = state.clone();
64///         Callback::from(move |e: InputEvent| {
65///             let input: HtmlInputElement = e.target_unchecked_into();
66///             state.set(input.value());
67///         })
68///     };
69///
70///     html! {
71///         <>
72///             <input type="text" placeholder="Debounced input" {oninput}/>
73///             <b>{ "Debounced state: " }</b> {&*state}
74///         </>
75///     }
76/// }
77/// ```
78#[hook]
79pub fn use_debounce_state<T, F>(init_fn: F, millis: u32) -> UseDebounceStateHandle<T>
80where
81    T: 'static,
82    F: FnOnce() -> T,
83{
84    let value = use_mut_ref(|| None);
85    let inner = use_state(init_fn);
86    let debounce = {
87        let value = value.clone();
88        let inner = inner.clone();
89        use_debounce(
90            move || {
91                let value = (*value.borrow_mut()).take();
92                if let Some(value) = value {
93                    inner.set(value);
94                }
95            },
96            millis,
97        )
98    };
99
100    let set = {
101        Rc::new(move |new_value: T| {
102            *value.borrow_mut() = Some(new_value);
103            debounce.run();
104        })
105    };
106
107    UseDebounceStateHandle { inner, set }
108}