leptos_use/
use_interval.rs

1use crate::utils::Pausable;
2use crate::{sendwrap_fn, use_interval_fn_with_options, UseIntervalFnOptions};
3use default_struct_builder::DefaultBuilder;
4use leptos::prelude::*;
5use leptos::reactive::wrappers::read::Signal;
6use std::rc::Rc;
7
8/// Reactive counter increases on every interval.
9///
10/// ## Demo
11///
12/// [Link to Demo](https://github.com/Synphonyte/leptos-use/tree/main/examples/use_interval)
13///
14/// ## Usage
15///
16/// ```
17/// # use leptos::prelude::*;
18/// # use leptos_use::{use_interval, UseIntervalReturn};
19/// #
20/// # #[component]
21/// # fn Demo() -> impl IntoView {
22/// let UseIntervalReturn {
23///     counter,
24///     reset,
25///     is_active,
26///     pause,
27///     resume
28/// }  = use_interval( 200 );
29/// # view! { }
30/// # }
31/// ```
32///
33/// ## SendWrapped Return
34///
35/// The returned closures `pause`, `resume` and `reset` are sendwrapped functions. They can
36/// only be called from the same thread that called `use_intersection_observer`.
37///
38/// ## Server-Side Rendering
39///
40/// On the server this function will simply be ignored.
41pub fn use_interval<N>(
42    interval: N,
43) -> UseIntervalReturn<
44    impl Fn() + Clone + Send + Sync,
45    impl Fn() + Clone + Send + Sync,
46    impl Fn() + Clone + Send + Sync,
47>
48where
49    N: Into<Signal<u64>>,
50{
51    use_interval_with_options(interval, UseIntervalOptions::default())
52}
53
54/// Version of [`use_interval`] that takes `UseIntervalOptions`. See [`use_interval`] for how to use.
55pub fn use_interval_with_options<N>(
56    interval: N,
57    options: UseIntervalOptions,
58) -> UseIntervalReturn<
59    impl Fn() + Clone + Send + Sync,
60    impl Fn() + Clone + Send + Sync,
61    impl Fn() + Clone + Send + Sync,
62>
63where
64    N: Into<Signal<u64>>,
65{
66    let UseIntervalOptions {
67        immediate,
68        callback,
69    } = options;
70
71    let (counter, set_counter) = signal(0u64);
72
73    let update = move || set_counter.update(|count| *count += 1);
74    let reset = sendwrap_fn!(move || set_counter.set(0));
75
76    let cb = move || {
77        update();
78        callback(counter.get());
79    };
80
81    let Pausable {
82        is_active,
83        pause,
84        resume,
85    } = use_interval_fn_with_options(
86        cb,
87        interval,
88        UseIntervalFnOptions {
89            immediate,
90            immediate_callback: false,
91        },
92    );
93
94    UseIntervalReturn {
95        counter: counter.into(),
96        reset,
97        is_active,
98        pause,
99        resume,
100    }
101}
102
103/// Options for [`use_interval_with_options`]
104#[derive(DefaultBuilder)]
105pub struct UseIntervalOptions {
106    /// Start the timer immediately. Defaults to `true`.
107    immediate: bool,
108
109    /// Callback on every interval.
110    callback: Rc<dyn Fn(u64)>,
111}
112
113impl Default for UseIntervalOptions {
114    fn default() -> Self {
115        Self {
116            immediate: true,
117            callback: Rc::new(|_: u64| {}),
118        }
119    }
120}
121
122/// Return type of [`use_interval`].
123#[derive(DefaultBuilder)]
124pub struct UseIntervalReturn<PauseFn, ResumeFn, ResetFn>
125where
126    PauseFn: Fn() + Clone + Send + Sync,
127    ResumeFn: Fn() + Clone + Send + Sync,
128    ResetFn: Fn() + Clone + Send + Sync,
129{
130    /// Counter signal that increases by one every interval.
131    pub counter: Signal<u64>,
132
133    /// Reset the counter to zero
134    pub reset: ResetFn,
135
136    /// A Signal that indicates whether the counter is active. `false` when paused.
137    pub is_active: Signal<bool>,
138
139    /// Temporarily pause the counter
140    pub pause: PauseFn,
141
142    /// Resume the counter
143    pub resume: ResumeFn,
144}