Skip to main content

Module _async

Module _async 

Source
Expand description

§Async

Freya runs futures on its own executor so async tasks can update reactive state directly. The async primitives below are the building blocks: use them for one-off tasks like timers, cancelable background work, or fire-and-forget requests.

§spawn

spawn starts a future tied to the current component scope. When the component unmounts, the task is automatically cancelled.

#[derive(PartialEq)]
struct DelayedCounter;

impl Component for DelayedCounter {
    fn render(&self) -> impl IntoElement {
        let mut count = use_state(|| 0);

        Button::new()
            .on_press(move |_| {
                spawn(async move {
                    // Some async work...
                    *count.write() += 1;
                });
            })
            .child(format!("Count: {}", count.read()))
    }
}

spawn returns a TaskHandle that you can use to cancel the task manually. Calling .owned() upgrades it to an OwnedTaskHandle that cancels the task when the last clone is dropped.

§spawn_forever

spawn_forever is like spawn but the task is attached to the root scope. It keeps running until the app exits or you cancel it explicitly, regardless of the component that started it.

Use it for app-wide background work (a sync loop, periodic refreshes, etc.) that should outlive the component that spawned it.

use_hook(|| {
    spawn_forever(async {
        loop {
            // App-level background loop
        }
    });
});

§use_future

use_future is a hook around spawn that exposes the future’s progress as reactive state. It is convenient when you want to render different UI for pending, loading, and fulfilled states without managing the task by hand.

#[derive(PartialEq)]
struct Greeting;

impl Component for Greeting {
    fn render(&self) -> impl IntoElement {
        let future = use_future(|| async {
            // Some async work...
            "Hello!".to_string()
        });

        match &*future.state() {
            FutureState::Pending | FutureState::Loading => "Loading...".to_string(),
            FutureState::Fulfilled(text) => text.clone(),
        }
    }
}

The returned FutureTask exposes start and cancel so you can restart or stop the future later.