Skip to content

Commit

Permalink
Add use_throttle (#4)
Browse files Browse the repository at this point in the history
* Add use_throttle
  • Loading branch information
jetli authored Mar 28, 2022
1 parent 9be6981 commit ea08968
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ fn counter() -> Html {
- `use_session_storage` - manages a value in `sessionStorage`.
- `use_before_unload` - shows browser alert when user try to reload or close the page.
- `use_debounce` - debounces a function.
- `use_throttle` - throttles a function.

### Lifecycles

Expand Down
2 changes: 1 addition & 1 deletion crates/yew-hooks/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "yew-hooks"
version = "0.1.48"
version = "0.1.49"
edition = "2018"
authors = ["Jet Li <[email protected]>"]
categories = ["gui", "wasm", "web-programming"]
Expand Down
2 changes: 2 additions & 0 deletions crates/yew-hooks/src/hooks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ mod use_set;
mod use_size;
mod use_state_ptr_eq;
mod use_swipe;
mod use_throttle;
mod use_timeout;
mod use_title;
mod use_toggle;
Expand Down Expand Up @@ -85,6 +86,7 @@ pub use use_set::*;
pub use use_size::*;
pub use use_state_ptr_eq::*;
pub use use_swipe::*;
pub use use_throttle::*;
pub use use_timeout::*;
pub use use_title::*;
pub use use_toggle::*;
Expand Down
118 changes: 118 additions & 0 deletions crates/yew-hooks/src/hooks/use_throttle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
use std::rc::Rc;

use yew::prelude::*;

use super::{use_mut_latest, use_timeout};

/// State handle for the [`use_throttle`] hook.
pub struct UseThrottleHandle {
run: Rc<dyn Fn()>,
cancel: Rc<dyn Fn()>,
}

impl UseThrottleHandle {
/// Run the throttle.
pub fn run(&self) {
(&self.run)()
}

/// Cancel the throttle.
pub fn cancel(&self) {
(&self.cancel)()
}
}

impl Clone for UseThrottleHandle {
fn clone(&self) -> Self {
Self {
run: self.run.clone(),
cancel: self.cancel.clone(),
}
}
}

/// A hook that throttles invoking a function, the function is only executed once every `millis`.
///
/// # Example
///
/// ```rust
/// # use yew::prelude::*;
/// #
/// use yew_hooks::use_throttle;
///
/// #[function_component(Throttle)]
/// fn throttle() -> Html {
/// let state = use_state(|| 0);
///
/// let throttle = {
/// let state = state.clone();
/// use_throttle(
/// move || {
/// state.set(*state + 1);
/// },
/// 2000,
/// )
/// };
///
/// let onclick = {
/// let throttle = throttle.clone();
/// Callback::from(move |_| throttle.run())
/// };
///
/// let oncancel = { Callback::from(move |_| throttle.cancel()) };
///
/// html! {
/// <div class="app">
/// <header class="app-header">
/// <div>
/// <button {onclick}>{ "Click fast!" }</button>
/// <button onclick={oncancel}>{ "Cancel throttle" }</button>
/// <p>
/// <b>{ "State: " }</b> {*state}
/// </p>
/// </div>
/// </header>
/// </div>
/// }
/// }
/// ```
pub fn use_throttle<Callback>(callback: Callback, millis: u32) -> UseThrottleHandle
where
Callback: FnMut() + 'static,
{
let throttled = use_mut_ref(|| false);
let callback_ref = use_mut_latest(callback);
let timeout = {
let throttled = throttled.clone();
use_timeout(
move || {
*throttled.borrow_mut() = false;
},
millis,
)
};

let run = {
let throttled = throttled.clone();
let timeout = timeout.clone();
Rc::new(move || {
let throttled_value = *throttled.borrow();
if !throttled_value {
let callback_ref = callback_ref.current();
let callback = &mut *callback_ref.borrow_mut();
callback();
*throttled.borrow_mut() = true;
timeout.reset();
}
})
};

let cancel = {
Rc::new(move || {
timeout.cancel();
*throttled.borrow_mut() = false;
})
};

UseThrottleHandle { run, cancel }
}
1 change: 1 addition & 0 deletions examples/yew-app/src/routes/home.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub fn home() -> Html {
<li><Link<AppRoute> to={AppRoute::UseSessionStorage} classes="app-link" >{ "use_session_storage" }</Link<AppRoute>> { " - manages a value in sessionStorage." }</li>
<li><Link<AppRoute> to={AppRoute::UseBeforeUnload} classes="app-link" >{ "use_before_unload" }</Link<AppRoute>> { " - shows browser alert when user try to reload or close the page." }</li>
<li><Link<AppRoute> to={AppRoute::UseDebounce} classes="app-link" >{ "use_debounce" }</Link<AppRoute>> { " - debounces a function." }</li>
<li><Link<AppRoute> to={AppRoute::UseThrottle} classes="app-link" >{ "use_throttle" }</Link<AppRoute>> { " - throttles a function." }</li>
</ul>

<h2>{ "Lifecycles" }</h2>
Expand Down
2 changes: 2 additions & 0 deletions examples/yew-app/src/routes/hooks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ mod use_set;
mod use_size;
mod use_state_ptr_eq;
mod use_swipe;
mod use_throttle;
mod use_timeout;
mod use_title;
mod use_toggle;
Expand Down Expand Up @@ -89,6 +90,7 @@ pub use use_set::*;
pub use use_size::*;
pub use use_state_ptr_eq::*;
pub use use_swipe::*;
pub use use_throttle::*;
pub use use_timeout::*;
pub use use_title::*;
pub use use_toggle::*;
Expand Down
40 changes: 40 additions & 0 deletions examples/yew-app/src/routes/hooks/use_throttle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use yew::prelude::*;

use yew_hooks::use_throttle;

/// `use_throttle` demo
#[function_component(UseThrottle)]
pub fn throttle() -> Html {
let state = use_state(|| 0);

let throttle = {
let state = state.clone();
use_throttle(
move || {
state.set(*state + 1);
},
2000,
)
};

let onclick = {
let throttle = throttle.clone();
Callback::from(move |_| throttle.run())
};

let oncancel = { Callback::from(move |_| throttle.cancel()) };

html! {
<div class="app">
<header class="app-header">
<div>
<button {onclick}>{ "Click fast!" }</button>
<button onclick={oncancel}>{ "Cancel throttle" }</button>
<p>
<b>{ "State: " }</b> {*state}
</p>
</div>
</header>
</div>
}
}
3 changes: 3 additions & 0 deletions examples/yew-app/src/routes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ pub enum AppRoute {
UseDebounce,
#[at("/use_debounce_state")]
UseDebounceState,
#[at("/use_throttle")]
UseThrottle,
#[not_found]
#[at("/page-not-found")]
PageNotFound,
Expand Down Expand Up @@ -173,6 +175,7 @@ pub fn switch(routes: &AppRoute) -> Html {
AppRoute::UseDefault => html! { <UseDefault /> },
AppRoute::UseDebounce => html! { <UseDebounce /> },
AppRoute::UseDebounceState => html! { <UseDebounceState /> },
AppRoute::UseThrottle => html! { <UseThrottle /> },
AppRoute::PageNotFound => html! { <Home /> },
}
}

0 comments on commit ea08968

Please sign in to comment.