Gestion de Estado

Por: Artiko
tauriestadostatemutexrust

Gestion de Estado

Los comandos en Tauri son funciones puras por defecto. Para compartir datos entre comandos, necesitas estado gestionado.

Estado basico

Definir y registrar

struct AppState {
    counter: std::sync::Mutex<i32>,
    api_url: String,
}

pub fn run() {
    tauri::Builder::default()
        .manage(AppState {
            counter: std::sync::Mutex::new(0),
            api_url: "https://api.ejemplo.com".into(),
        })
        .invoke_handler(tauri::generate_handler![increment, get_count, get_api_url])
        .run(tauri::generate_context!())
        .expect("error");
}

Acceder desde comandos

#[tauri::command]
fn increment(state: tauri::State<AppState>) -> i32 {
    let mut counter = state.counter.lock().unwrap();
    *counter += 1;
    *counter
}

#[tauri::command]
fn get_count(state: tauri::State<AppState>) -> i32 {
    *state.counter.lock().unwrap()
}

#[tauri::command]
fn get_api_url(state: tauri::State<AppState>) -> String {
    state.api_url.clone()
}

tauri::State<T> inyecta automaticamente el estado registrado con .manage().

Mutex: por que y cuando

Rust no permite mutacion compartida sin sincronizacion. Si tu estado cambia:

use std::sync::Mutex;

struct Database {
    items: Mutex<Vec<String>>,
}

#[tauri::command]
fn add_item(state: tauri::State<Database>, item: String) {
    state.items.lock().unwrap().push(item);
}

#[tauri::command]
fn list_items(state: tauri::State<Database>) -> Vec<String> {
    state.items.lock().unwrap().clone()
}

Si el estado es inmutable (configuracion, URLs), no necesitas Mutex:

struct Config {
    version: String,  // Solo lectura, sin Mutex
}

Multiples estados

Puedes registrar varios tipos de estado:

struct UserState {
    name: Mutex<String>,
}

struct SettingsState {
    theme: String,
}

pub fn run() {
    tauri::Builder::default()
        .manage(UserState { name: Mutex::new("Anonimo".into()) })
        .manage(SettingsState { theme: "dark".into() })
        .invoke_handler(tauri::generate_handler![get_user, get_theme])
        .run(tauri::generate_context!())
        .expect("error");
}

#[tauri::command]
fn get_user(state: tauri::State<UserState>) -> String {
    state.name.lock().unwrap().clone()
}

#[tauri::command]
fn get_theme(state: tauri::State<SettingsState>) -> String {
    state.theme.clone()
}

Estado con AppHandle

Si necesitas acceder al estado fuera de un comando (ej: en un listener o setup):

use tauri::Manager;

pub fn run() {
    tauri::Builder::default()
        .manage(AppState { counter: Mutex::new(0), api_url: "...".into() })
        .setup(|app| {
            let state = app.state::<AppState>();
            println!("API: {}", state.api_url);
            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error");
}

Patron: estado con inicializacion asincrona

struct DbPool {
    pool: sqlx::SqlitePool,
}

pub fn run() {
    tauri::Builder::default()
        .setup(|app| {
            let pool = tauri::async_runtime::block_on(async {
                sqlx::SqlitePool::connect("sqlite:app.db").await.unwrap()
            });
            app.manage(DbPool { pool });
            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error");
}

Resumen


← Llamar al Frontend desde Rust | Indice | Siguiente: Sistema de Plugins →