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}