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