# Gestión de estado

> El patrón de estado de CrossFly — sin binding reactivo, ViewModel manual + onUI + repaint.

Source: https://crossfly.dev/es/docs/data-and-services/state-management — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Gestión de estado

Si vienes de React/Flutter/Compose, prepárate para la mayor diferencia: **no hay data-binding
reactivo**. Nada de `useState`/`Observable`/`setState()` que se redibuja solo. El modelo es
**imperativo + invalidación explícita** — el "porqué" está en
[Estado y flujo de datos](/docs/concepts/state-and-data-flow).

## El patrón
El estado vive en **campos comunes** de un objeto tuyo (un ViewModel/servicio). Cuando cambia, **tú actualizas
el widget** y llamas a `repaint()` — si vino de otro hilo, dentro de `Component.onUI(...)`.
```java
class HomeVM {
   List<Cliente> clientes = new ArrayList<>();
}

public class TelaHome extends Window {
   private final HomeVM vm = new HomeVM();
   private ListView<Cliente> lista;

   @Override public void onShow() throws Exception {
      super.onShow();
      setLayout(new VerticalLayout());
      add(LAY_FILL, lista = new ListView<>());
      carregar();
   }

   private void carregar() {
      new Thread(() -> {
         List<Cliente> dados = repositorio.buscarTudo();   // trabajo pesado, thread de fondo
         Component.onUI(() -> {                             // vuelve al paint thread
            vm.clientes = dados;
            lista.setItems(dados);                          // actualiza el widget
            Component.repaint();                            // pide nuevo frame
         });
      }).start();
   }
}
```

## Estado efímero vs. de aplicación
| Tipo | Dónde vive | ¿Sobrevive a la navegación? |
|---|---|---|
| **efímero de pantalla** | campos de la `Window` | no — desaparece al salir de la pantalla |
| **de aplicación** | un singleton/servicio compartido | sí — persiste entre pantallas |

Elige según el ámbito: el filtro de una búsqueda es efímero; el usuario autenticado es de aplicación.

## Buenas prácticas
- Un **ViewModel por pantalla** concentra el estado y la lógica; la `Window` solo conecta UI ↔ VM.
- Estado compartido entre pantallas → **servicio/singleton**, no campo estático disperso.
- Vuelve siempre a la UI con `onUI(...)` antes de tocar widgets desde un hilo de fondo.

## Errores comunes
- Esperar que cambiar el modelo actualice la UI solo — **no se actualiza**; llama a `setX(...)` + `repaint()`.
- Guardar estado de app en campos de la `Window` (se pierde al navegar).

## Véase también
- Concepto: [Estado y flujo de datos](/docs/concepts/state-and-data-flow) · [El paint thread](/docs/concepts/the-paint-thread)
- [Persistencia con SQLite](/docs/data-and-services/storage-sqlite) · [Trabajo en segundo plano](/docs/data-and-services/background-work)
- Arquitectura de app: [best-practices](/docs/best-practices)
