yew_hooks/hooks/
use_throttle.rs

1use std::rc::Rc;
2
3use yew::prelude::*;
4
5use super::{use_mut_latest, use_timeout};
6
7/// State handle for the [`use_throttle`] hook.
8pub struct UseThrottleHandle {
9    run: Rc<dyn Fn()>,
10    cancel: Rc<dyn Fn()>,
11}
12
13impl UseThrottleHandle {
14    /// Run the throttle.
15    pub fn run(&self) {
16        (self.run)();
17    }
18
19    /// Cancel the throttle.
20    pub fn cancel(&self) {
21        (self.cancel)();
22    }
23}
24
25impl Clone for UseThrottleHandle {
26    fn clone(&self) -> Self {
27        Self {
28            run: self.run.clone(),
29            cancel: self.cancel.clone(),
30        }
31    }
32}
33
34/// A hook that throttles invoking a function, the function is only executed once every `millis`.
35///
36/// # Example
37///
38/// ```rust
39/// # use yew::prelude::*;
40/// #
41/// use yew_hooks::prelude::*;
42///
43/// #[function_component(Throttle)]
44/// fn throttle() -> Html {
45///     let state = use_state(|| 0);
46///
47///     let throttle = {
48///         let state = state.clone();
49///         use_throttle(
50///             move || {
51///                 state.set(*state + 1);
52///             },
53///             2000,
54///         )
55///     };
56///
57///     let onclick = {
58///         let throttle = throttle.clone();
59///         Callback::from(move |_| throttle.run())
60///     };
61///
62///     let oncancel = { Callback::from(move |_| throttle.cancel()) };
63///
64///     html! {
65///         <>
66///             <button {onclick}>{ "Click fast!" }</button>
67///             <button onclick={oncancel}>{ "Cancel throttle" }</button>
68///             <b>{ "State: " }</b> {*state}
69///         </>
70///     }
71/// }
72/// ```
73#[hook]
74pub fn use_throttle<Callback>(callback: Callback, millis: u32) -> UseThrottleHandle
75where
76    Callback: FnMut() + 'static,
77{
78    let throttled = use_mut_ref(|| false);
79    let callback_ref = use_mut_latest(callback);
80    let timeout = {
81        let throttled = throttled.clone();
82        use_timeout(
83            move || {
84                *throttled.borrow_mut() = false;
85            },
86            millis,
87        )
88    };
89
90    let run = {
91        let throttled = throttled.clone();
92        let timeout = timeout.clone();
93        Rc::new(move || {
94            let throttled_value = *throttled.borrow();
95            if !throttled_value {
96                let callback_ref = callback_ref.current();
97                let callback = &mut *callback_ref.borrow_mut();
98                callback();
99                *throttled.borrow_mut() = true;
100                timeout.reset();
101            }
102        })
103    };
104
105    let cancel = {
106        Rc::new(move || {
107            timeout.cancel();
108            *throttled.borrow_mut() = false;
109        })
110    };
111
112    UseThrottleHandle { run, cancel }
113}