Start timer on component mount

Value::with_connect creates a value together with a generator which keeps it up to date. The generator runs when the value starts being observed, i.e. when the component which renders it gets mounted. The DropResource it returns is dropped when nothing observes the value anymore, i.e. the component gets unmounted. So the timer below runs only while the counter is on the page:

    use vertigo::{dom, get_driver, Value};

    // Starts the interval when the counter gets mounted,
    // returned DropResource stops it when the counter gets unmounted.
    let counter = Value::with_connect(0, |counter| {
        let counter = counter.clone();
        get_driver().set_interval(1000, move || counter.change(|c| *c += 1))
    });

    dom! {
        <div>"Seconds on this page: " {counter}</div>
    }

The generator may set the value, but the destructor of the DropResource should only tear down the timer (or other external handler) - setting a value from there is ignored. During server-side rendering intervals don't fire, so the server renders the initial value.

Asynchronous task

Keep in mind that bind! with an async block only creates a future, which does nothing until it's spawned with get_driver().spawn(...). The bind_spawn! macro does both - creates an event handler which spawns the task each time it's called:

    use vertigo::{bind_spawn, dom, get_driver, Value};

    let progress = Value::new(0);

    // Spawns the task on every click
    let start = bind_spawn!(progress, |_| async move {
        for i in 0..=100 {
            progress.set(i);
            get_driver().sleep(20).await;
        }
    });

    dom! {
        <div>
            <button on_click={start}>"Start"</button>
            " " {progress} "%"
        </div>
    }