Gestión de estado
En una aplicación Tauri, a menudo necesitas hacer un seguimiento del estado actual de tu aplicación o gestionar el ciclo de vida de cosas asociadas a ella. Tauri proporciona una forma sencilla de gestionar el estado de tu aplicación mediante la API Manager, y leerlo cuando se llaman a los comandos.
Aquí tienes un ejemplo sencillo:
use tauri::{Builder, Manager};
struct AppData { welcome_message: &'static str,}
fn main() { Builder::default() .setup(|app| { app.manage(AppData { welcome_message: "Welcome to Tauri!", }); Ok(()) }) .run(tauri::generate_context!()) .unwrap();}Más adelante puedes acceder a tu estado con cualquier tipo que implemente el trait Manager, por ejemplo la instancia de App:
let data = app.state::<AppData>();Para obtener más información, incluyendo cómo acceder al estado en comandos, consulta la sección Acceder al estado.
Mutabilidad
Sección titulada “Mutabilidad”En Rust, no puedes mutar directamente valores que se comparten entre varios hilos o cuando la propiedad está controlada a través de un puntero compartido como Arc (o State de Tauri). Hacerlo podría causar carreras de datos (por ejemplo, dos escrituras sucediendo simultáneamente).
Para solucionar esto, puedes usar un concepto conocido como mutabilidad interior. Por ejemplo, el Mutex de la biblioteca estándar se puede usar para envolver tu estado. Esto te permite bloquear el valor cuando necesitas modificarlo y desbloquearlo cuando hayas terminado.
use std::sync::Mutex;
use tauri::{Builder, Manager};
#[derive(Default)]struct AppState { counter: u32,}
fn main() { Builder::default() .setup(|app| { app.manage(Mutex::new(AppState::default())); Ok(()) }) .run(tauri::generate_context!()) .unwrap();}El estado se puede modificar ahora bloqueando el mutex:
let state = app.state::<Mutex<AppState>>();
// Lock the mutex to get mutable access:let mut state = state.lock().unwrap();
// Modify the state:state.counter += 1;Al final del alcance, o cuando el MutexGuard se destruya de otro modo, el mutex se desbloquea automáticamente para que otras partes de tu aplicación puedan acceder y mutar los datos que contiene.
Cuándo usar un mutex asíncrono
Sección titulada “Cuándo usar un mutex asíncrono”Citando la documentación de Tokio, a menudo está bien usar el Mutex de la biblioteca estándar en lugar de un mutex asíncrono como el que proporciona Tokio:
Contrariamente a la creencia popular, está bien y a menudo se prefiere usar el Mutex ordinario de la biblioteca estándar en código asíncrono... El caso de uso principal para el mutex asíncrono es proporcionar acceso mutable compartido a recursos de E/S tales como una conexión a base de datos.
Es una buena idea leer la documentación enlazada por completo para entender las compensaciones entre los dos. Una razón por la que necesitarías un mutex asíncrono es si necesitas mantener el MutexGuard a través de puntos de await.
¿Necesitas Arc?
Sección titulada “¿Necesitas Arc?”Es común ver el uso de Arc en Rust para compartir la propiedad de un valor entre múltiples hilos (usualmente combinado con un Mutex en la forma Arc<Mutex<T>>). Sin embargo, no necesitas usar Arc para las cosas almacenadas en State porque Tauri lo hará por ti.
En caso de que los requisitos de tiempo de vida de State te impidan mover tu estado a un nuevo hilo, en su lugar puedes mover un AppHandle al hilo y luego recuperar tu estado como se muestra a continuación en la sección “Acceder al estado con el trait Manager”. Los AppHandle son deliberadamente baratos de clonar para casos de uso como este.
Acceder al estado
Sección titulada “Acceder al estado”Acceder al estado en comandos
Sección titulada “Acceder al estado en comandos”#[tauri::command]fn increase_counter(state: State<'_, Mutex<AppState>>) -> u32 { let mut state = state.lock().unwrap(); state.counter += 1; state.counter}Para obtener más información sobre los comandos, consulta Llamar a Rust desde el Frontend.
Comandos asíncronos
Sección titulada “Comandos asíncronos”Si estás utilizando comandos async y quieres usar el Mutex asíncrono de Tokio, puedes configurarlo de la misma manera y acceder al estado así:
#[tauri::command]async fn increase_counter(state: State<'_, Mutex<AppState>>) -> Result<u32, ()> { let mut state = state.lock().await; state.counter += 1; Ok(state.counter)}Ten en cuenta que el tipo devuelto debe ser Result si usas comandos asíncronos.
Acceder al estado con el trait Manager
Sección titulada “Acceder al estado con el trait Manager”A veces puede que necesites acceder al estado fuera de los comandos, como en un hilo diferente o en un controlador de eventos como on_window_event. En tales casos, puedes usar el método state() de los tipos que implementan el trait Manager (como el AppHandle) para obtener el estado:
use std::sync::Mutex;use tauri::{Builder, Window, WindowEvent, Manager};
#[derive(Default)]struct AppState { counter: u32,}
// In an event handler:fn on_window_event(window: &Window, _event: &WindowEvent) { // Get a handle to the app so we can get the global state. let app_handle = window.app_handle(); let state = app_handle.state::<Mutex<AppState>>();
// Lock the mutex to mutably access the state. let mut state = state.lock().unwrap(); state.counter += 1;}
fn main() { Builder::default() .setup(|app| { app.manage(Mutex::new(AppState::default())); Ok(()) }) .on_window_event(on_window_event) .run(tauri::generate_context!()) .unwrap();}Este método es útil cuando no puedes confiar en la inyección de comandos. Por ejemplo, si necesitas mover el estado a un hilo donde usar un AppHandle sea más fácil, o si no te encuentras en el contexto de un comando.
Incompatibilidad de tipos
Sección titulada “Incompatibilidad de tipos”Si lo prefieres, puedes envolver tu estado con un alias de tipo para evitar este error:
use std::sync::Mutex;
#[derive(Default)]struct AppStateInner { counter: u32,}
type AppState = Mutex<AppStateInner>;Sin embargo, asegúrate de usar el alias de tipo tal como está y no envolverlo en un Mutex por segunda vez; de lo contrario, te encontrarás con el mismo problema.
© 2026 Colaboradores de Tauri. CC-BY / MIT