leptos-use/src/watch_with_options.rs

205 lines
5.9 KiB
Rust
Raw Normal View History

use crate::filter_builder_methods;
use crate::utils::{create_filter_wrapper, DebounceOptions, FilterOptions, ThrottleOptions};
use default_struct_builder::DefaultBuilder;
2023-05-29 01:52:03 +01:00
use leptos::*;
use std::cell::RefCell;
use std::rc::Rc;
2023-05-29 01:52:03 +01:00
2023-07-24 21:16:59 +02:00
/// A version of `leptos::watch` but with additional options.
///
/// ## Immediate
///
2023-07-24 21:16:59 +02:00
/// This is the same as for `leptos::watch`. But you don't have to specify it.
/// By default its set to `false`.
/// If `immediate` is `true`, the `callback` will run immediately (this is also true if throttled/debounced).
2023-07-03 14:46:59 +01:00
/// If it's `false`, the `callback` will run only after
/// the first change is detected of any signal that is accessed in `deps`.
///
/// ```
/// # use leptos::*;
2023-09-12 15:24:32 +01:00
/// # use leptos::logging::log;
/// # use leptos_use::{watch_with_options, WatchOptions};
/// #
2023-07-27 18:06:36 +01:00
/// # pub fn Demo() -> impl IntoView {
/// let (num, set_num) = create_signal(0);
///
/// watch_with_options(
/// move || num.get(),
/// move |num, _, _| {
2023-06-09 23:10:33 +01:00
/// log!("Number {}", num);
/// },
/// WatchOptions::default().immediate(true),
2023-06-09 23:10:33 +01:00
/// ); // > "Number 0"
///
/// set_num.set(1); // > "Number 1"
2023-07-27 18:06:36 +01:00
/// # view! { }
/// # }
/// ```
///
/// ## Filters
///
/// The callback can be throttled or debounced. Please see [`watch_throttled`] and [`watch_debounced`] for details.
///
/// ```
/// # use leptos::*;
2023-09-12 15:24:32 +01:00
/// # use leptos::logging::log;
/// # use leptos_use::{watch_with_options, WatchOptions};
/// #
2023-07-27 18:06:36 +01:00
/// # pub fn Demo() -> impl IntoView {
/// # let (num, set_num) = create_signal(0);
/// #
/// watch_with_options(
/// move || num.get(),
/// move |num, _, _| {
2023-06-09 23:10:33 +01:00
/// log!("Number {}", num);
/// },
/// WatchOptions::default().throttle(100.0), // there's also `throttle_with_options`
/// );
2023-07-27 18:06:36 +01:00
/// # view! { }
/// # }
/// ```
///
/// ```
/// # use leptos::*;
2023-09-12 15:24:32 +01:00
/// # use leptos::logging::log;
/// # use leptos_use::{watch_with_options, WatchOptions};
/// #
2023-07-27 18:06:36 +01:00
/// # pub fn Demo() -> impl IntoView {
/// # let (num, set_num) = create_signal(0);
/// #
/// watch_with_options(
/// move || num.get(),
/// move |num, _, _| {
/// log!("number {}", num);
/// },
/// WatchOptions::default().debounce(100.0), // there's also `debounce_with_options`
/// );
2023-07-27 18:06:36 +01:00
/// # view! { }
/// # }
/// ```
///
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
2023-07-24 21:16:59 +02:00
/// called exactly once when `watch()` is executed.
2023-07-14 22:43:19 +01:00
///
/// ## See also
///
/// * [`watch_throttled`]
/// * [`watch_debounced`]
/// Version of `watch` that accepts `WatchOptions`. See [`watch`] for how to use.
pub fn watch_with_options<W, T, DFn, CFn>(
2023-05-29 01:52:03 +01:00
deps: DFn,
callback: CFn,
options: WatchOptions,
2023-05-29 01:52:03 +01:00
) -> impl Fn() + Clone
where
DFn: Fn() -> W + 'static,
CFn: Fn(&W, Option<&W>, Option<T>) -> T + Clone + 'static,
W: Clone + 'static,
T: Clone + 'static,
2023-05-29 01:52:03 +01:00
{
let cur_deps_value: Rc<RefCell<Option<W>>> = Rc::new(RefCell::new(None));
let prev_deps_value: Rc<RefCell<Option<W>>> = Rc::new(RefCell::new(None));
let prev_callback_value: Rc<RefCell<Option<T>>> = Rc::new(RefCell::new(None));
2023-06-13 17:48:32 +01:00
let wrapped_callback = {
let cur_deps_value = Rc::clone(&cur_deps_value);
let prev_deps_value = Rc::clone(&prev_deps_value);
2023-07-03 14:46:59 +01:00
let prev_callback_val = Rc::clone(&prev_callback_value);
2023-06-13 17:48:32 +01:00
move || {
#[cfg(debug_assertions)]
let prev = SpecialNonReactiveZone::enter();
let ret = callback(
2023-06-13 17:48:32 +01:00
cur_deps_value
.borrow()
.as_ref()
.expect("this will not be called before there is deps value"),
prev_deps_value.borrow().as_ref(),
2023-07-03 14:46:59 +01:00
prev_callback_val.take(),
);
#[cfg(debug_assertions)]
SpecialNonReactiveZone::exit(prev);
ret
2023-06-13 17:48:32 +01:00
}
};
let filtered_callback =
create_filter_wrapper(options.filter.filter_fn(), wrapped_callback.clone());
2023-05-29 01:52:03 +01:00
2023-07-24 21:16:59 +02:00
leptos::watch(
deps,
move |deps_value, previous_deps_value, did_run_before| {
cur_deps_value.replace(Some(deps_value.clone()));
prev_deps_value.replace(previous_deps_value.cloned());
let callback_value = if options.immediate && did_run_before.is_none() {
Some(wrapped_callback())
} else {
filtered_callback().take()
};
prev_callback_value.replace(callback_value);
},
options.immediate,
)
2023-07-27 18:06:36 +01:00
// create_effect(move |did_run_before| {
2023-07-24 21:16:59 +02:00
// if !is_active.get() {
// return;
// }
//
// let deps_value = deps();
//
// if !options.immediate && did_run_before.is_none() {
// prev_deps_value.replace(Some(deps_value));
// return;
// }
//
// cur_deps_value.replace(Some(deps_value.clone()));
//
//
// prev_deps_value.replace(Some(deps_value));
// });
//
//
2023-05-29 01:52:03 +01:00
}
/// Options for `watch_with_options`
#[derive(DefaultBuilder, Default)]
pub struct WatchOptions {
/// If `immediate` is true, the `callback` will run immediately.
/// If it's `false, the `callback` will run only after
/// the first change is detected of any signal that is accessed in `deps`.
2023-06-14 16:15:03 +01:00
/// Defaults to `false`.
immediate: bool,
2023-06-14 16:15:03 +01:00
/// Allows to debounce or throttle the callback. Defaults to no filter.
filter: FilterOptions,
}
impl WatchOptions {
filter_builder_methods!(
/// the watch callback
filter
);
}
2023-07-24 21:16:59 +02:00
#[deprecated(since = "0.7.0", note = "Use `leptos::watch` instead")]
#[inline(always)]
2023-07-27 18:06:36 +01:00
pub fn watch<W, T, DFn, CFn>(deps: DFn, callback: CFn) -> impl Fn() + Clone
2023-07-24 21:16:59 +02:00
where
DFn: Fn() -> W + 'static,
CFn: Fn(&W, Option<&W>, Option<T>) -> T + Clone + 'static,
W: Clone + 'static,
T: Clone + 'static,
{
2023-07-27 18:06:36 +01:00
leptos::watch(deps, callback, false)
2023-07-24 21:16:59 +02:00
}