fixed use_timeout_fn to be SSR safe

This commit is contained in:
Maccesch 2024-07-31 01:15:20 +01:00
parent f0d60e5d49
commit da56771900
3 changed files with 76 additions and 48 deletions

View file

@ -3,6 +3,12 @@
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.11.3] - 2024-07-31
### Fix 🍕
- Made `use_timeout_fn` SSR-safe
## [0.11.2] - 2024-07-30 ## [0.11.2] - 2024-07-30
### Change 🔥 ### Change 🔥

View file

@ -1,6 +1,6 @@
[package] [package]
name = "leptos-use" name = "leptos-use"
version = "0.11.2" version = "0.11.3"
edition = "2021" edition = "2021"
authors = ["Marc-Stefan Cassola"] authors = ["Marc-Stefan Cassola"]
categories = ["gui", "web-programming"] categories = ["gui", "web-programming"]

View file

@ -1,9 +1,5 @@
use leptos::leptos_dom::helpers::TimeoutHandle;
use leptos::*; use leptos::*;
use std::cell::Cell;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::rc::Rc;
use std::time::Duration;
/// Wrapper for `setTimeout` with controls. /// Wrapper for `setTimeout` with controls.
/// ///
@ -31,6 +27,11 @@ use std::time::Duration;
/// # view! { } /// # view! { }
/// # } /// # }
/// ``` /// ```
///
/// ## Server-Side Rendering
///
/// On the server the callback will never be run. The returned functions are all no-ops and
/// `is_pending` will always be `false`.
pub fn use_timeout_fn<CbFn, Arg, D>( pub fn use_timeout_fn<CbFn, Arg, D>(
callback: CbFn, callback: CbFn,
delay: D, delay: D,
@ -40,65 +41,86 @@ where
Arg: 'static, Arg: 'static,
D: Into<MaybeSignal<f64>>, D: Into<MaybeSignal<f64>>,
{ {
let delay = delay.into();
let (is_pending, set_pending) = create_signal(false); let (is_pending, set_pending) = create_signal(false);
let timer = Rc::new(Cell::new(None::<TimeoutHandle>)); let start;
let stop;
let clear = { #[cfg(not(feature = "ssr"))]
let timer = Rc::clone(&timer); {
use leptos::leptos_dom::helpers::TimeoutHandle;
use std::cell::Cell;
use std::rc::Rc;
use std::time::Duration;
move || { let delay = delay.into();
if let Some(timer) = timer.take() {
timer.clear(); let timer = Rc::new(Cell::new(None::<TimeoutHandle>));
let clear = {
let timer = Rc::clone(&timer);
move || {
if let Some(timer) = timer.take() {
timer.clear();
}
} }
} };
};
let stop = { stop = {
let clear = clear.clone(); let clear = clear.clone();
move || { move || {
set_pending.set(false); set_pending.set(false);
clear(); clear();
} }
}; };
let start = { start = {
let timer = Rc::clone(&timer); let timer = Rc::clone(&timer);
let callback = callback.clone(); let callback = callback.clone();
move |arg: Arg| { move |arg: Arg| {
set_pending.set(true); set_pending.set(true);
let handle = set_timeout_with_handle( let handle = set_timeout_with_handle(
{ {
let timer = Rc::clone(&timer); let timer = Rc::clone(&timer);
let callback = callback.clone(); let callback = callback.clone();
move || { move || {
set_pending.set(false); set_pending.set(false);
timer.set(None); timer.set(None);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
let prev = SpecialNonReactiveZone::enter(); let prev = SpecialNonReactiveZone::enter();
callback(arg); callback(arg);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
SpecialNonReactiveZone::exit(prev); SpecialNonReactiveZone::exit(prev);
} }
}, },
Duration::from_millis(delay.get_untracked() as u64), Duration::from_millis(delay.get_untracked() as u64),
) )
.ok(); .ok();
timer.set(handle); timer.set(handle);
} }
}; };
on_cleanup(clear); on_cleanup(clear);
}
#[cfg(feature = "ssr")]
{
let _ = set_pending;
let _ = callback;
let _ = delay;
start = move |_: Arg| ();
stop = move || ();
}
UseTimeoutFnReturn { UseTimeoutFnReturn {
is_pending: is_pending.into(), is_pending: is_pending.into(),