zng::handler

Macro async_hn

source
macro_rules! async_hn {
    ($($tt:tt)+) => { ... };
}
Expand description

Declare an async clone-move event handler.

The macro input is a closure with optional clone-move variables, internally it uses async_clmv_fn! so the input is the same syntax.

§Examples

The example declares an async event handler for the on_click property.

on_click = async_hn!(|_| {
    println!("Clicked!");

    task::run(async {
        println!("In other thread!");
    }).await;

    println!("Back in UI thread, in a widget update.");
});

The closure input is ClickArgs for this property. Note that if you want to use the event args you must annotate the input type.

on_click = async_hn!(|args: ClickArgs| {
    println!("Clicked {} {} times!", WIDGET.id(), args.click_count);
    
});

Internally the async_clmv_fn! macro is used so you can clone-move variables into the handler.

let enabled = var(true);

// ..

on_click = async_hn!(enabled, |args: ClickArgs| {
    enabled.set(false);

    task::run(async move {
        println!("do something {}", args.click_count);
    }).await;

    enabled.set(true);
});

// can still use after:
text = enabled.map(|&e| if e { "Click Me!" } else { "Busy.." });
enabled;

In the example above only a clone of enabled is moved into the handler. Note that handlers always capture by move, if enabled was not listed in the clone-move section it would not be available after the handler is created. See async_clmv_fn! for details.

The example also demonstrates a common pattern with async handlers, most events are only raised when the widget is enabled, so you can disable the widget while the async task is running. This way you don’t block the UI running a task but the user cannot spawn a second task while the first is still running.

§Futures and Clone-Move

You may want to always clone-move captures for async handlers, because they then automatically get cloned again for each event. This needs to happen because you can have more then one handler task running at the same type, and both want access to the captured variables.

This second cloning can be avoided by using the async_hn_once! macro instead, but only if you expect a single event.