leptos_use/watch_pausable.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
use crate::{watch_with_options, WatchOptions};
use leptos::*;
/// Pausable [`watch`].
///
/// ## Demo
///
/// [Link to Demo](https://github.com/Synphonyte/leptos-use/tree/main/examples/watch_pausable)
///
/// ## Usage
///
/// ```
/// # use leptos::*;
/// # use leptos::logging::log;
/// # use leptos_use::{watch_pausable, WatchPausableReturn};
/// #
/// # pub fn Demo() -> impl IntoView {
/// let (source, set_source) = create_signal("foo".to_string());
///
/// let WatchPausableReturn {
/// stop,
/// pause,
/// resume,
/// ..
/// } = watch_pausable(
/// move || source.get(),
/// |v, _, _| {
/// log!("Changed to {}", v);
/// },
/// );
///
/// set_source.set("bar".to_string()); // > "Changed to bar"
///
/// pause();
///
/// set_source.set("foobar".to_string()); // (nothing happens)
///
/// resume();
///
/// set_source.set("hello".to_string()); // > "Changed to hello"
/// # view! { }
/// # }
/// ```
///
/// There's also [`watch_pausable_with_options`] which takes the same options as [`watch`].
///
/// ## Server-Side Rendering
///
/// On the server this works just fine except if you throttle or debounce in which case the callback
/// will never be called except if you set `immediate` to `true` in which case the callback will be
/// called exactly once.
///
/// ## See also
///
/// * `leptos::watch`
pub fn watch_pausable<W, T, DFn, CFn>(
deps: DFn,
callback: CFn,
) -> WatchPausableReturn<impl Fn() + Clone, impl Fn() + Clone, impl Fn() + Clone>
where
DFn: Fn() -> W + 'static,
CFn: Fn(&W, Option<&W>, Option<T>) -> T + Clone + 'static,
W: Clone + 'static,
T: Clone + 'static,
{
watch_pausable_with_options(deps, callback, WatchOptions::default())
}
/// Version of `watch_pausable` that accepts `WatchOptions`. See [`watch_pausable`] for how to use.
pub fn watch_pausable_with_options<W, T, DFn, CFn>(
deps: DFn,
callback: CFn,
options: WatchOptions,
) -> WatchPausableReturn<impl Fn() + Clone, impl Fn() + Clone, impl Fn() + Clone>
where
DFn: Fn() -> W + 'static,
CFn: Fn(&W, Option<&W>, Option<T>) -> T + Clone + 'static,
W: Clone + 'static,
T: Clone + 'static,
{
let (is_active, set_active) = create_signal(true);
let pausable_callback = move |val: &W, prev_val: Option<&W>, prev_ret: Option<Option<T>>| {
if is_active.get_untracked() {
Some(callback(val, prev_val, prev_ret.unwrap_or(None)))
} else {
None
}
};
let stop = watch_with_options(deps, pausable_callback, options);
let pause = move || {
set_active.set(false);
};
let resume = move || {
set_active.set(true);
};
WatchPausableReturn {
stop,
pause,
resume,
is_active: is_active.into(),
}
}
/// Return type of [`watch_pausable`]
pub struct WatchPausableReturn<StopFn, PauseFn, ResumeFn>
where
StopFn: Fn() + Clone,
PauseFn: Fn() + Clone,
ResumeFn: Fn() + Clone,
{
/// Stops the watcher
pub stop: StopFn,
/// Pauses the watcher
pub pause: PauseFn,
/// Resumes the watcher
pub resume: ResumeFn,
/// Whether the watcher is active (not paused). This doesn't reflect if the watcher has been stopped
pub is_active: Signal<bool>,
}