leptos_use/
whenever.rs

1use crate::{WatchOptions, watch_with_options};
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/// > Make sure you follow the [instructions in Server-Side Rendering](https://leptos-use.rs/server_side_rendering.html).
84///
85/// On the server this works just fine except if you throttle or debounce in which case the callback
86/// will never be called except if you set `immediate` to `true` in which case the callback will be
87/// called exactly once.
88pub fn whenever<T, DFn, CFn>(source: DFn, callback: CFn) -> impl Fn() + Clone + Send + Sync
89where
90    DFn: Fn() -> bool + 'static,
91    CFn: Fn(bool, Option<bool>, Option<T>) -> T + Clone + 'static,
92    T: Clone + 'static,
93{
94    whenever_with_options(source, callback, WatchOptions::default())
95}
96
97/// Version of `whenever` that accepts `WatchOptions`. See [`whenever`] for how to use.
98pub fn whenever_with_options<T, DFn, CFn>(
99    source: DFn,
100    callback: CFn,
101    options: WatchOptions,
102) -> impl Fn() + Clone + Send + Sync
103where
104    DFn: Fn() -> bool + 'static,
105    CFn: Fn(bool, Option<bool>, Option<T>) -> T + Clone + 'static,
106    T: Clone + 'static,
107{
108    watch_with_options(
109        source,
110        move |value, prev_value, prev_return| {
111            if *value {
112                Some(callback(
113                    *value,
114                    prev_value.copied(),
115                    prev_return.unwrap_or_default(),
116                ))
117            } else {
118                None
119            }
120        },
121        options,
122    )
123}