leptos_use/
whenever.rs

1use crate::{watch_with_options, WatchOptions};
2
3/// Shorthand for watching a signal to be `true`.
4///
5/// ## Usage
6///
7/// ```
8/// # use leptos::prelude::*;
9/// # use leptos::logging::log;
10/// # use leptos_use::whenever;
11/// #
12/// # pub fn Demo() -> impl IntoView {
13/// let (is_ready, set_ready) = signal(false);
14///
15/// whenever(move || is_ready.get(), |v, _, _| log!("{}", v));
16/// #
17/// #     view! { }
18/// # }
19/// ```
20///
21/// ### Callback Function
22///
23/// Same as [`fn@crate::watch`], the callback will be called with `callback(input, prev_input, prev_return)`.
24///
25/// ```
26/// # use leptos::prelude::*;
27/// # use leptos::logging::log;
28/// # use leptos_use::whenever;
29/// #
30/// # pub fn Demo() -> impl IntoView {
31/// # let (is_ready, set_ready) = signal(false);
32/// whenever(move || is_ready.get(), |value, prev_value, _| {
33///     log!("before: {prev_value:?}; now: {value}");
34/// });
35/// #
36/// #     view! { }
37/// # }
38/// ```
39///
40/// ### Computed
41///
42/// Same as [`fn@crate::watch`], you can pass a getter function to calculate on each change.
43///
44/// ```
45/// # use leptos::prelude::*;
46/// # use leptos::logging::log;
47/// # use leptos_use::whenever;
48/// #
49/// # pub fn Demo() -> impl IntoView {
50/// # let (counter, set_counter) = signal(0);
51/// whenever(
52///     move || counter.get() == 7,
53///     |_, _, _| log!("counter is 7 now!"),
54/// );
55/// #
56/// #     view! { }
57/// # }
58/// ```
59///
60/// ### Options
61///
62/// Options and defaults are same as [`fn@watch_with_options`].
63///
64/// ```
65/// # use leptos::prelude::*;
66/// # use leptos::logging::log;
67/// # use leptos_use::{WatchOptions, whenever_with_options};
68/// #
69/// # pub fn Demo() -> impl IntoView {
70/// # let (counter, set_counter) = signal(0);
71/// whenever_with_options(
72///     move || counter.get() == 7,
73///     |_, _, _| log!("counter is 7 now!"),
74///     WatchOptions::default().immediate(true),
75/// );
76/// #
77/// #     view! { }
78/// # }
79/// ```
80///
81/// ## Server-Side Rendering
82///
83/// On the server this works just fine except if you throttle or debounce in which case the callback
84/// will never be called except if you set `immediate` to `true` in which case the callback will be
85/// called exactly once.
86pub fn whenever<T, DFn, CFn>(source: DFn, callback: CFn) -> impl Fn() + Clone + Send + Sync
87where
88    DFn: Fn() -> bool + 'static,
89    CFn: Fn(bool, Option<bool>, Option<T>) -> T + Clone + 'static,
90    T: Clone + 'static,
91{
92    whenever_with_options(source, callback, WatchOptions::default())
93}
94
95/// Version of `whenever` that accepts `WatchOptions`. See [`whenever`] for how to use.
96pub fn whenever_with_options<T, DFn, CFn>(
97    source: DFn,
98    callback: CFn,
99    options: WatchOptions,
100) -> impl Fn() + Clone + Send + Sync
101where
102    DFn: Fn() -> bool + 'static,
103    CFn: Fn(bool, Option<bool>, Option<T>) -> T + Clone + 'static,
104    T: Clone + 'static,
105{
106    watch_with_options(
107        source,
108        move |value, prev_value, prev_return| {
109            if *value {
110                Some(callback(
111                    *value,
112                    prev_value.copied(),
113                    prev_return.unwrap_or_default(),
114                ))
115            } else {
116                None
117            }
118        },
119        options,
120    )
121}