-
-
Notifications
You must be signed in to change notification settings - Fork 41
/
use_timeout_fn.rs
127 lines (106 loc) · 2.96 KB
/
use_timeout_fn.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 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.
///
/// ## Demo
///
/// [Link to Demo](https://github.com/Synphonyte/leptos-use/tree/main/examples/use_timeout_fn)
///
/// ## Usage
///
/// ```
/// # use leptos::*;
/// # use leptos_use::{use_timeout_fn, UseTimeoutFnReturn};
/// #
/// # #[component]
/// # fn Demo() -> impl IntoView {
/// let UseTimeoutFnReturn { start, stop, is_pending, .. } = use_timeout_fn(
/// |i: i32| {
/// // do sth
/// },
/// 3000.0
/// );
///
/// start(3);
/// #
/// # view! { }
/// # }
/// ```
pub fn use_timeout_fn<CbFn, Arg, D>(
callback: CbFn,
delay: D,
) -> UseTimeoutFnReturn<impl Fn(Arg) + Clone, Arg, impl Fn() + Clone>
where
CbFn: Fn(Arg) + Clone + 'static,
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 clear = {
let timer = Rc::clone(&timer);
move || {
if let Some(timer) = timer.take() {
timer.clear();
}
}
};
let stop = {
let clear = clear.clone();
move || {
set_pending.set(false);
clear();
}
};
let start = {
let timer = Rc::clone(&timer);
let callback = callback.clone();
move |arg: Arg| {
set_pending.set(true);
let handle = set_timeout_with_handle(
{
let timer = Rc::clone(&timer);
let callback = callback.clone();
move || {
set_pending.set(false);
timer.set(None);
#[cfg(debug_assertions)]
let prev = SpecialNonReactiveZone::enter();
callback(arg);
#[cfg(debug_assertions)]
SpecialNonReactiveZone::exit(prev);
}
},
Duration::from_millis(delay.get_untracked() as u64),
)
.ok();
timer.set(handle);
}
};
on_cleanup(clear);
UseTimeoutFnReturn {
is_pending: is_pending.into(),
start,
stop,
_marker: PhantomData,
}
}
/// Return type of [`use_timeout_fn`].
pub struct UseTimeoutFnReturn<StartFn, StartArg, StopFn>
where
StartFn: Fn(StartArg) + Clone,
StopFn: Fn() + Clone,
{
/// Whether the timeout is pending. When the `callback` is called this is set to `false`.
pub is_pending: Signal<bool>,
/// Start the timeout. The `callback` will be called after `delay` milliseconds.
pub start: StartFn,
/// Stop the timeout. If the timeout was still pending the `callback` is not called.
pub stop: StopFn,
_marker: PhantomData<StartArg>,
}