1- use dioxus:: prelude:: * ;
2- use futures:: {
3- channel:: mpsc:: { self , UnboundedSender as Sender } ,
4- StreamExt ,
1+ use crate :: { use_timeout, TimeoutHandle , UseTimeout } ;
2+ use dioxus:: {
3+ dioxus_core:: SpawnIfAsync ,
4+ hooks:: use_signal,
5+ signals:: { Signal , Writable } ,
56} ;
67use std:: time:: Duration ;
78
89/// The interface for calling a debounce.
910///
1011/// See [`use_debounce`] for more information.
11- pub struct UseDebounce < T : ' static > {
12- sender : Signal < Sender < T > > ,
12+ #[ derive( Clone , Copy , PartialEq ) ]
13+ pub struct UseDebounce < Args : ' static > {
14+ current_handle : Signal < Option < TimeoutHandle > > ,
15+ timeout : UseTimeout < Args > ,
1316}
1417
15- impl < T > UseDebounce < T > {
18+ impl < Args > UseDebounce < Args > {
1619 /// Start the debounce countdown, resetting it if already started.
17- pub fn action ( & mut self , data : T ) {
18- self . sender . write ( ) . unbounded_send ( data) . ok ( ) ;
20+ pub fn action ( & mut self , args : Args ) {
21+ self . cancel ( ) ;
22+ self . current_handle . set ( Some ( self . timeout . action ( args) ) ) ;
1923 }
20- }
21-
22- // Manually implement Clone, Copy, and PartialEq as #[derive] thinks that T needs to implement these (it doesn't).
23- impl < T > Clone for UseDebounce < T > {
24- fn clone ( & self ) -> Self {
25- * self
26- }
27- }
28-
29- impl < T > Copy for UseDebounce < T > { }
3024
31- impl < T > PartialEq for UseDebounce < T > {
32- fn eq ( & self , other : & Self ) -> bool {
33- self . sender == other. sender
25+ /// Cancel the debounce action.
26+ pub fn cancel ( & mut self ) {
27+ if let Some ( handle) = self . current_handle . take ( ) {
28+ handle. cancel ( ) ;
29+ }
3430 }
3531}
3632
@@ -41,54 +37,92 @@ impl<T> PartialEq for UseDebounce<T> {
4137///
4238/// # Examples
4339///
40+ /// Example of using a debounce:
4441/// ```rust
4542/// use dioxus::prelude::*;
4643/// use dioxus_time::use_debounce;
4744/// use std::time::Duration;
4845///
4946/// #[component]
5047/// fn App() -> Element {
48+ /// // Create a two second debounce.
49+ /// // This will print "ran" after two seconds since the last action call.
5150/// let mut debounce = use_debounce(Duration::from_secs(2), |_| println!("ran"));
5251///
5352/// rsx! {
5453/// button {
5554/// onclick: move |_| {
55+ /// // Call the debounce.
5656/// debounce.action(());
5757/// },
5858/// "Click!"
5959/// }
6060/// }
6161/// }
6262/// ```
63- pub fn use_debounce < T > ( time : Duration , cb : impl FnOnce ( T ) + Copy + ' static ) -> UseDebounce < T > {
64- use_hook ( || {
65- let ( sender, mut receiver) = mpsc:: unbounded ( ) ;
66- let debouncer = UseDebounce {
67- sender : Signal :: new ( sender) ,
68- } ;
69-
70- spawn ( async move {
71- let mut current_task: Option < Task > = None ;
72-
73- loop {
74- if let Some ( data) = receiver. next ( ) . await {
75- if let Some ( task) = current_task. take ( ) {
76- task. cancel ( ) ;
77- }
78-
79- current_task = Some ( spawn ( async move {
80- #[ cfg( not( target_family = "wasm" ) ) ]
81- tokio:: time:: sleep ( time) . await ;
82-
83- #[ cfg( target_family = "wasm" ) ]
84- gloo_timers:: future:: sleep ( time) . await ;
85-
86- cb ( data) ;
87- } ) ) ;
88- }
89- }
90- } ) ;
63+ ///
64+ /// #### Cancelling A Debounce
65+ /// If you need to cancel the currently active debounce, you can call [`UseDebounce::cancel`]:
66+ /// ```rust
67+ /// use dioxus::prelude::*;
68+ /// use dioxus_time::use_debounce;
69+ /// use std::time::Duration;
70+ ///
71+ /// #[component]
72+ /// fn App() -> Element {
73+ /// let mut debounce = use_debounce(Duration::from_secs(5), |_| println!("ran"));
74+ ///
75+ /// rsx! {
76+ /// button {
77+ /// // Start the debounce on click.
78+ /// onclick: move |_| debounce.action(()),
79+ /// "Action!"
80+ /// }
81+ /// button {
82+ /// // Cancel the debounce on click.
83+ /// onclick: move |_| debounce.cancel(),
84+ /// "Cancel!"
85+ /// }
86+ /// }
87+ /// }
88+ /// ```
89+ ///
90+ /// ### Async Debounce
91+ /// Debounces can accept an async callback:
92+ /// ```rust
93+ /// use dioxus::prelude::*;
94+ /// use dioxus_time::use_debounce;
95+ /// use std::time::Duration;
96+ ///
97+ /// #[component]
98+ /// fn App() -> Element {
99+ /// // Create a two second debounce that uses some async/await.
100+ /// let mut debounce = use_debounce(Duration::from_secs(2), |_| async {
101+ /// println!("debounce called!");
102+ /// tokio::time::sleep(Duration::from_secs(2)).await;
103+ /// println!("after async");
104+ /// });
105+ ///
106+ /// rsx! {
107+ /// button {
108+ /// onclick: move |_| {
109+ /// // Call the debounce.
110+ /// debounce.action(());
111+ /// },
112+ /// "Click!"
113+ /// }
114+ /// }
115+ /// }
116+ /// ```
117+ pub fn use_debounce < Args : ' static , MaybeAsync : SpawnIfAsync < Marker > , Marker > (
118+ duration : Duration ,
119+ callback : impl FnMut ( Args ) -> MaybeAsync + ' static ,
120+ ) -> UseDebounce < Args > {
121+ let timeout = use_timeout ( duration, callback) ;
122+ let current_handle = use_signal ( || None ) ;
91123
92- debouncer
93- } )
124+ UseDebounce {
125+ timeout,
126+ current_handle,
127+ }
94128}
0 commit comments