Skip to content

Commit

Permalink
fixed use_timeout_fn to be SSR safe
Browse files Browse the repository at this point in the history
  • Loading branch information
maccesch committed Jul 31, 2024
1 parent f0d60e5 commit da56771
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 48 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
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).

## [0.11.3] - 2024-07-31

### Fix 🍕

- Made `use_timeout_fn` SSR-safe

## [0.11.2] - 2024-07-30

### Change 🔥
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "leptos-use"
version = "0.11.2"
version = "0.11.3"
edition = "2021"
authors = ["Marc-Stefan Cassola"]
categories = ["gui", "web-programming"]
Expand Down
116 changes: 69 additions & 47 deletions src/use_timeout_fn.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
use leptos::leptos_dom::helpers::TimeoutHandle;
use leptos::*;
use std::cell::Cell;
use std::marker::PhantomData;
use std::rc::Rc;
use std::time::Duration;

/// Wrapper for `setTimeout` with controls.
///
Expand Down Expand Up @@ -31,6 +27,11 @@ use std::time::Duration;
/// # 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>(
callback: CbFn,
delay: D,
Expand All @@ -40,65 +41,86 @@ where
Arg: 'static,
D: Into<MaybeSignal<f64>>,
{
let delay = delay.into();

let (is_pending, set_pending) = create_signal(false);

let timer = Rc::new(Cell::new(None::<TimeoutHandle>));
let start;
let stop;

#[cfg(not(feature = "ssr"))]
{
use leptos::leptos_dom::helpers::TimeoutHandle;
use std::cell::Cell;
use std::rc::Rc;
use std::time::Duration;

let delay = delay.into();

let timer = Rc::new(Cell::new(None::<TimeoutHandle>));

let clear = {
let timer = Rc::clone(&timer);
let clear = {
let timer = Rc::clone(&timer);

move || {
if let Some(timer) = timer.take() {
timer.clear();
move || {
if let Some(timer) = timer.take() {
timer.clear();
}
}
}
};
};

let stop = {
let clear = clear.clone();
stop = {
let clear = clear.clone();

move || {
set_pending.set(false);
clear();
}
};
move || {
set_pending.set(false);
clear();
}
};

start = {
let timer = Rc::clone(&timer);
let callback = callback.clone();

move |arg: Arg| {
set_pending.set(true);

let start = {
let timer = Rc::clone(&timer);
let callback = callback.clone();
let handle = set_timeout_with_handle(
{
let timer = Rc::clone(&timer);
let callback = callback.clone();

move |arg: Arg| {
set_pending.set(true);
move || {
set_pending.set(false);
timer.set(None);

let handle = set_timeout_with_handle(
{
let timer = Rc::clone(&timer);
let callback = callback.clone();
#[cfg(debug_assertions)]
let prev = SpecialNonReactiveZone::enter();

move || {
set_pending.set(false);
timer.set(None);
callback(arg);

#[cfg(debug_assertions)]
let prev = SpecialNonReactiveZone::enter();
#[cfg(debug_assertions)]
SpecialNonReactiveZone::exit(prev);
}
},
Duration::from_millis(delay.get_untracked() as u64),
)
.ok();

callback(arg);
timer.set(handle);
}
};

#[cfg(debug_assertions)]
SpecialNonReactiveZone::exit(prev);
}
},
Duration::from_millis(delay.get_untracked() as u64),
)
.ok();
on_cleanup(clear);
}

timer.set(handle);
}
};
#[cfg(feature = "ssr")]
{
let _ = set_pending;
let _ = callback;
let _ = delay;

on_cleanup(clear);
start = move |_: Arg| ();
stop = move || ();
}

UseTimeoutFnReturn {
is_pending: is_pending.into(),
Expand Down

0 comments on commit da56771

Please sign in to comment.