diff --git a/examples/Makefile.toml b/examples/Makefile.toml index a6265d8d1..1a741ca2b 100644 --- a/examples/Makefile.toml +++ b/examples/Makefile.toml @@ -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", diff --git a/examples/timer/Cargo.toml b/examples/timer/Cargo.toml new file mode 100644 index 000000000..ecb9aa1a4 --- /dev/null +++ b/examples/timer/Cargo.toml @@ -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" diff --git a/examples/timer/Makefile.toml b/examples/timer/Makefile.toml new file mode 100644 index 000000000..ab9175602 --- /dev/null +++ b/examples/timer/Makefile.toml @@ -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" diff --git a/examples/timer/README.md b/examples/timer/README.md new file mode 100644 index 000000000..5affd52f5 --- /dev/null +++ b/examples/timer/README.md @@ -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/) diff --git a/examples/timer/index.html b/examples/timer/index.html new file mode 100644 index 000000000..75fa1f12a --- /dev/null +++ b/examples/timer/index.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/examples/timer/public/favicon.ico b/examples/timer/public/favicon.ico new file mode 100644 index 000000000..2ba8527cb Binary files /dev/null and b/examples/timer/public/favicon.ico differ diff --git a/examples/timer/rust-toolchain.toml b/examples/timer/rust-toolchain.toml new file mode 100644 index 000000000..5d56faf9a --- /dev/null +++ b/examples/timer/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/examples/timer/src/lib.rs b/examples/timer/src/lib.rs new file mode 100644 index 000000000..5d474da8a --- /dev/null +++ b/examples/timer/src/lib.rs @@ -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, +
+
"Count A (fixed interval of 1000 ms)"
+
{count_a}
+
"Count B (dynamic interval, currently " {interval} " ms)"
+
{count_b}
+ () { + set_interval(value); + } + }/> +
+ } +} + +/// Hook to wrap the underlying `setInterval` call and make it reactive w.r.t. +/// possible changes of the timer interval. +pub fn use_interval(cx: Scope, interval_millis: T, f: F) +where + F: Fn() + Clone + 'static, + T: Into> + 'static, +{ + let interval_millis = interval_millis.into(); + create_effect(cx, move |prev_handle: Option| { + // 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") + }); +} diff --git a/examples/timer/src/main.rs b/examples/timer/src/main.rs new file mode 100644 index 000000000..d1c553d31 --- /dev/null +++ b/examples/timer/src/main.rs @@ -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, + + } + }) +}