2023-06-09 23:10:33 +01:00
|
|
|
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_use::{watch_pausable, WatchPausableReturn};
|
|
|
|
/// #
|
|
|
|
/// # pub fn Demo(cx: Scope) -> impl IntoView {
|
|
|
|
/// let (source, set_source) = create_signal(cx, "foo".to_string());
|
|
|
|
///
|
|
|
|
/// let WatchPausableReturn {
|
|
|
|
/// stop,
|
|
|
|
/// pause,
|
|
|
|
/// resume,
|
|
|
|
/// ..
|
|
|
|
/// } = watch_pausable(
|
|
|
|
/// cx,
|
2023-06-21 13:09:00 +02:00
|
|
|
/// move || source.get(),
|
2023-06-09 23:10:33 +01:00
|
|
|
/// |v, _, _| {
|
|
|
|
/// log!("Changed to {}", v);
|
|
|
|
/// },
|
|
|
|
/// );
|
|
|
|
///
|
2023-06-21 13:09:00 +02:00
|
|
|
/// set_source.set("bar".to_string()); // > "Changed to bar"
|
2023-06-09 23:10:33 +01:00
|
|
|
///
|
|
|
|
/// pause();
|
|
|
|
///
|
2023-06-21 13:09:00 +02:00
|
|
|
/// set_source.set("foobar".to_string()); // (nothing happens)
|
2023-06-09 23:10:33 +01:00
|
|
|
///
|
|
|
|
/// resume();
|
|
|
|
///
|
2023-06-21 13:09:00 +02:00
|
|
|
/// set_source.set("hello".to_string()); // > "Changed to hello"
|
2023-06-09 23:10:33 +01:00
|
|
|
/// # view! { cx, }
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// There's also [`watch_pausable_with_options`] which takes the same options as [`watch`].
|
|
|
|
///
|
2023-07-14 22:43:19 +01:00
|
|
|
/// ## 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.
|
|
|
|
///
|
2023-06-09 23:10:33 +01:00
|
|
|
/// ## See also
|
|
|
|
///
|
|
|
|
/// * [`watch`]
|
|
|
|
pub fn watch_pausable<W, T, DFn, CFn>(
|
|
|
|
cx: Scope,
|
|
|
|
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(cx, 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>(
|
|
|
|
cx: Scope,
|
|
|
|
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(cx, 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(cx, deps, pausable_callback, options);
|
|
|
|
|
|
|
|
let pause = move || {
|
2023-06-21 13:09:00 +02:00
|
|
|
set_active.set(false);
|
2023-06-09 23:10:33 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
let resume = move || {
|
2023-06-21 13:09:00 +02:00
|
|
|
set_active.set(true);
|
2023-06-09 23:10:33 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
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>,
|
|
|
|
}
|