Working with External State

This guide will help you integrate your Dioxus application with some external state like a different thread or a websocket connection.

Working with non-reactive State

Coroutines are great tool for dealing with non-reactive (state you don't render directly) state within your application.

You can store your state inside the coroutine async block and communicate with the coroutine with messages from any child components.

src/use_coroutine.rs
// import futures::StreamExt to use the next() method
use futures::StreamExt;
let mut response_state = use_signal(|| None);
let tx = use_coroutine(move |mut rx| async move {
    // Define your state before the loop
    let mut state = reqwest::Client::new();
    let mut cache: HashMap<String, String> = HashMap::new();
    loop {
        // Loop and wait for the next message
        if let Some(request) = rx.next().await {
            // Resolve the message
            let response = if let Some(response) = cache.get(&request) {
                response.clone()
            } else {
                let response = state
                    .get(&request)
                    .send()
                    .await
                    .unwrap()
                    .text()
                    .await
                    .unwrap();
                cache.insert(request, response.clone());
                response
            };
            response_state.set(Some(response));
        } else {
            break;
        }
    }
});
// Send a message to the coroutine
tx.send("https://example.com".to_string());
// Get the current state of the coroutine
let response = response_state.read();

Making Reactive State External

If you have some reactive state (state that is rendered), that you want to modify from another thread, you can use a signal that is sync. Signals take an optional second generic value with information about syncness. Sync signals have a slightly higher overhead than thread local signals, but they can be used in a multithreaded environment.

src/use_coroutine.rs
use dioxus::prelude::*;

fn main() {
    launch(app);
}

fn app() -> Element {
    let mut signal = use_signal_sync(|| 0);

    use_hook(|| {
        std::thread::spawn(move || loop {
            std::thread::sleep(std::time::Duration::from_secs(1));
            // You can easily update the signal from a different thread
            signal += 1;
        });
    });

    rsx! {
        button { onclick: move |_| signal += 1, "Increase" }
        "{signal}"
    }
}