leptos_use/watch_debounced.rs
1use crate::{utils::DebounceOptions, watch_with_options, WatchOptions};
2use default_struct_builder::DefaultBuilder;
3use leptos::prelude::*;
4
5/// A debounced version of [`watch`].
6///
7/// ## Demo
8///
9/// [Link to Demo](https://github.com/Synphonyte/leptos-use/tree/main/examples/watch_debounced)
10///
11/// ## Usage
12///
13/// ```
14/// # use leptos::prelude::*;
15/// # use leptos::logging::log;
16/// # use leptos_use::watch_debounced;
17/// #
18/// # pub fn Demo() -> impl IntoView {
19/// # let (source, set_source) = signal(0);
20/// #
21/// watch_debounced(
22/// move || source.get(),
23/// move |_, _, _| {
24/// log!("changed!");
25/// },
26/// 500.0,
27/// );
28///
29/// # view! { }
30/// # }
31/// ```
32///
33/// This really is only shorthand shorthand for `watch_with_options(deps, callback, WatchOptions::default().debounce(ms))`.
34///
35/// Please note that if the current component is cleaned up before the debounced callback is called, the debounced callback will not be called.
36///
37/// There's also [`watch_debounced_with_options`] where you can specify the other watch options (except `filter`).
38///
39/// ```
40/// # use leptos::prelude::*;
41/// # use leptos::logging::log;
42/// # use leptos_use::{watch_debounced_with_options, WatchDebouncedOptions};
43/// #
44/// # pub fn Demo() -> impl IntoView {
45/// # let (source, set_source) = signal(0);
46/// #
47/// watch_debounced_with_options(
48/// move || source.get(),
49/// move |_, _, _| {
50/// log!("changed!");
51/// },
52/// 500.0,
53/// WatchDebouncedOptions::default().max_wait(Some(1000.0)),
54/// );
55///
56/// # view! { }
57/// # }
58/// ```
59///
60/// ## Recommended Reading
61///
62/// - [**Debounce vs Throttle**: Definitive Visual Guide](https://redd.one/blog/debounce-vs-throttle)
63/// - [Debouncing and Throttling Explained Through Examples](https://css-tricks.com/debouncing-throttling-explained-examples/)
64///
65/// ## Server-Side Rendering
66///
67/// On the server the callback
68/// will never be called except if you set `immediate` to `true` in which case the callback will be
69/// called exactly once.
70///
71/// ## See also
72///
73/// * `leptos::watch`
74/// * [`fn@crate::watch_throttled`]
75pub fn watch_debounced<W, T, DFn, CFn>(
76 deps: DFn,
77 callback: CFn,
78 ms: f64,
79) -> impl Fn() + Clone + Send + Sync
80where
81 DFn: Fn() -> W + 'static,
82 CFn: Fn(&W, Option<&W>, Option<T>) -> T + Clone + 'static,
83 W: Clone + 'static,
84 T: Clone + 'static,
85{
86 watch_with_options(deps, callback, WatchOptions::default().debounce(ms))
87}
88
89/// Version of `watch_debounced` that accepts `WatchDebouncedOptions`.
90/// See [`watch_debounced`] for how to use.
91pub fn watch_debounced_with_options<W, T, DFn, CFn>(
92 deps: DFn,
93 callback: CFn,
94 ms: f64,
95 options: WatchDebouncedOptions,
96) -> impl Fn() + Clone + Send + Sync
97where
98 DFn: Fn() -> W + 'static,
99 CFn: Fn(&W, Option<&W>, Option<T>) -> T + Clone + 'static,
100 W: Clone + 'static,
101 T: Clone + 'static,
102{
103 watch_with_options(
104 deps,
105 callback,
106 WatchOptions::default()
107 .debounce_with_options(ms, DebounceOptions::default().max_wait(options.max_wait))
108 .immediate(options.immediate),
109 )
110}
111
112/// Options for [`watch_debounced_with_options`].
113#[derive(DefaultBuilder, Default)]
114pub struct WatchDebouncedOptions {
115 /// If `immediate` is false, the `callback` will not run immediately but only after
116 /// the first change is detected of any signal that is accessed in `deps`.
117 /// Defaults to `true`.
118 immediate: bool,
119
120 /// The maximum time allowed to be delayed before the callback invoked.
121 /// In milliseconds.
122 /// Same as [`DebounceOptions::max_wait`]
123 #[builder(into)]
124 pub max_wait: Signal<Option<f64>>,
125}