examples: add timer example with reactive use_interval hook (#925)

This commit is contained in:
Fabian Keller 2023-04-23 21:27:47 +02:00 committed by GitHub
parent 72f8bf4e20
commit 9badfa997b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 124 additions and 0 deletions

View file

@ -24,6 +24,7 @@ CARGO_MAKE_CRATE_WORKSPACE_MEMBERS = [
"ssr_modes_axum",
"tailwind",
"tailwind_csr_trunk",
"timer",
"todo_app_sqlite",
"todo_app_sqlite_axum",
"todo_app_sqlite_viz",

24
examples/timer/Cargo.toml Normal file
View file

@ -0,0 +1,24 @@
[package]
name = "timer"
version = "0.1.0"
edition = "2021"
[profile.release]
codegen-units = 1
lto = true
[dependencies]
leptos = { path = "../../leptos" }
console_log = "1"
log = "0.4"
console_error_panic_hook = "0.1.7"
wasm-bindgen = "0.2"
[dependencies.web-sys]
version = "0.3"
features = [
"Window",
]
[dev-dependencies]
wasm-bindgen-test = "0.3.0"

View file

@ -0,0 +1,9 @@
[tasks.build]
command = "cargo"
args = ["+nightly", "build-all-features"]
install_crate = "cargo-all-features"
[tasks.check]
command = "cargo"
args = ["+nightly", "check-all-features"]
install_crate = "cargo-all-features"

7
examples/timer/README.md Normal file
View file

@ -0,0 +1,7 @@
# Leptos Timer Example
This example creates a simple timer based on `setInterval` in a client side rendered app with Rust and WASM.
To run it, just issue the `trunk serve --open` command in the example root. This will build the app, run it, and open a new browser to serve it.
> If you don't have `trunk` installed, [click here for install instructions.](https://trunkrs.dev/)

View file

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<head>
<link data-trunk rel="rust" data-wasm-opt="z"/>
<link data-trunk rel="icon" type="image/ico" href="/public/favicon.ico"/>
</head>
<body></body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"

61
examples/timer/src/lib.rs Normal file
View file

@ -0,0 +1,61 @@
use leptos::{leptos_dom::helpers::IntervalHandle, *};
use std::time::Duration;
/// Timer example, demonstrating the use of `use_interval`.
#[component]
pub fn TimerDemo(cx: Scope) -> impl IntoView {
// count_a updates with a fixed interval of 1000 ms, whereas count_b has a dynamic
// update interval.
let (count_a, set_count_a) = create_signal(cx, 0_i32);
let (count_b, set_count_b) = create_signal(cx, 0_i32);
let (interval, set_interval) = create_signal(cx, 1000);
use_interval(cx, 1000, move || {
set_count_a.update(|c| *c = *c + 1);
});
use_interval(cx, interval, move || {
set_count_b.update(|c| *c = *c + 1);
});
view! { cx,
<div>
<div>"Count A (fixed interval of 1000 ms)"</div>
<div>{count_a}</div>
<div>"Count B (dynamic interval, currently " {interval} " ms)"</div>
<div>{count_b}</div>
<input prop:value=interval on:input=move |ev| {
if let Ok(value) = event_target_value(&ev).parse::<u64>() {
set_interval(value);
}
}/>
</div>
}
}
/// Hook to wrap the underlying `setInterval` call and make it reactive w.r.t.
/// possible changes of the timer interval.
pub fn use_interval<T, F>(cx: Scope, interval_millis: T, f: F)
where
F: Fn() + Clone + 'static,
T: Into<MaybeSignal<u64>> + 'static,
{
let interval_millis = interval_millis.into();
create_effect(cx, move |prev_handle: Option<IntervalHandle>| {
// effects get their previous return value as an argument
// each time the effect runs, it will return the interval handle
// so if we have a previous one, we cancel it
if let Some(prev_handle) = prev_handle {
prev_handle.clear();
};
// here, we return the handle
set_interval_with_handle(
f.clone(),
// this is the only reactive access, so this effect will only
// re-run when the interval changes
Duration::from_millis(interval_millis.get()),
)
.expect("could not create interval")
});
}

View file

@ -0,0 +1,12 @@
use leptos::*;
use timer::TimerDemo;
pub fn main() {
_ = console_log::init_with_level(log::Level::Debug);
console_error_panic_hook::set_once();
mount_to_body(|cx| {
view! { cx,
<TimerDemo />
}
})
}