Comunicación entre ventanas
Dos ventanas no se hablan: hablan con el core. Los tres patrones —el evento dirigido, el estado compartido y el difundido— y por qué el core como único árbitro es la respuesta correcta y no un rodeo.
Por qué el core es el árbitro
Dos ventanas son dos webviews, y dos webviews son dos contextos aislados por el sistema operativo —la propiedad del nivel 4.3—. No hay memoria compartida, no hay variables comunes, y el único sitio con acceso a las dos es el proceso que las creó.
Que el canal directo no exista fuerza una propiedad valiosa: el estado compartido vive en un solo sitio y ese sitio es el core. Una arquitectura donde dos ventanas se sincronizan entre sí tiene dos copias de la verdad y necesita una regla para resolver los desacuerdos; con el core como árbitro, no hay desacuerdo posible.
Los tres patrones
1 · El evento dirigido. El core avisa a una ventana concreta, por su etiqueta.
// Desde un comando invocado por la ventana de ajustes:app.emit_to("main", "preferencia-cambiada", &nueva)?;Es el más directo y sirve cuando sabes exactamente a quién le importa. El nivel 20 entra en el sistema de eventos completo; aquí basta con saber que el destino se nombra por etiqueta.
2 · El estado compartido en el core. El dato vive en el core y las ventanas lo piden.
// El estado es del programa, no de ninguna ventana. Nivel 22.#[tauri::command]async fn set_tema(state: tauri::State<'_, Ajustes>, tema: String) -> Result<(), ErrorPayload> { state.set_tema(&tema)?; // se guarda donde debe Ok(())}Es el patrón correcto para cualquier cosa que no sea de una ventana concreta: las preferencias, el proyecto abierto, la sesión. Y se combina con el primero: el comando guarda y después emite para que quien lo esté mostrando se entere.
3 · La difusión. El core avisa a todas.
app.emit("catalogo-actualizado", &resumen)?; // a todas las ventanasSirve cuando el cambio afecta a cualquiera que esté escuchando y no quieres llevar la cuenta de quién hay abierto. Es cómodo y tiene un coste: cada ventana recibe el evento aunque no le sirva, lo que en una aplicación con muchas ventanas y eventos frecuentes se nota.
Cuál elegir
La última fila es un recordatorio útil: no todo estado es compartido. Meter en el core lo que solo le importa a una vista añade cruces del puente y complejidad sin ganar nada.
El error clásico
Es este, y aparece siempre igual: la ventana principal guarda el estado en su JavaScript, la ventana de ajustes le pide el valor por un evento, y la principal se lo contesta por otro.
Funciona, y tiene tres problemas que se manifiestan en orden:
- Si la ventana principal está cerrada, no hay a quién preguntar. Y una ventana de ajustes que solo funciona con la principal abierta es una limitación que nadie pidió.
- El estado se pierde al recargar. Un recargado de la webview —que en desarrollo pasa a cada rato— borra la verdad de la aplicación.
- Hay dos copias en cuanto la segunda ventana guarda la suya, y toca escribir la lógica de reconciliación que el core habría hecho innecesaria.
La corrección es directa y es la del nivel 4.1: si tiene consecuencias fuera de una pantalla, va en el core. Una preferencia que afecta a dos ventanas es, por definición, de las que tienen consecuencias fuera de una pantalla.