Skip to main content

euv_ui/hook/use_timer/
fn.rs

1use super::*;
2
3/// Obtains the [`UseTimer`] registered against the current hook context
4/// slot.
5///
6/// Behaves like `HookContext::use_hook` - the same handle is returned on
7/// every render at the same hook index, so the tick count survives
8/// re-renders.
9///
10/// The interval is created once, on the first render, and is cleared
11/// automatically when the component unmounts. A period of zero is
12/// treated as one millisecond: a zero-delay interval is a busy loop
13/// that would starve the renderer.
14///
15/// # Arguments
16///
17/// - `u32` - The period in milliseconds.
18///
19/// # Returns
20///
21/// - `UseTimer` - The handle, with `get_ticks()` returning the reactive
22///   `Signal<u64>`.
23pub fn use_timer(interval_ms: u32) -> UseTimer {
24    let handle: UseTimer = HookContext::use_hook(|| UseTimer::new(interval_ms));
25    // The interval is a browser timer. `App::use_interval` reaches for
26    // `window` to register it, and `window` does not exist on a host
27    // build — the call would abort the process rather than return. The
28    // timer therefore only runs in a browser, and a host build gets a
29    // handle whose tick count simply never moves.
30    #[cfg(target_arch = "wasm32")]
31    {
32        let ticks: Signal<u64> = handle.get_ticks();
33        App::use_interval(interval_ms.max(1) as i32, move || {
34            let current: u64 = ticks.get();
35            ticks.set(current + 1);
36        });
37    }
38    handle
39}
40
41/// Schedules `callback` to run once, `delay_ms` milliseconds from now.
42///
43/// The callback is dropped if the component unmounts before the delay
44/// elapses, so a timeout cannot fire into a component that is gone.
45///
46/// # Arguments
47///
48/// - `u32` - The delay in milliseconds.
49/// - `F` - The callback to run.
50pub fn use_timeout<F>(delay_ms: u32, callback: F)
51where
52    F: FnOnce() + 'static,
53{
54    let cancelled: Signal<bool> = App::use_signal(|| false);
55    schedule_after(delay_ms, move || {
56        if cancelled.get() {
57            return;
58        }
59        callback();
60    });
61    App::use_cleanup(move || {
62        cancelled.set(true);
63    });
64}