# Gerência de estado

> O padrão de estado do CrossFly — sem binding reativo, ViewModel manual + onUI + repaint.

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

# Gerência de estado

Se você vem de React/Flutter/Compose, prepare-se para a maior diferença: **não há data-binding
reativo**. Nada de `useState`/`Observable`/`setState()` que redesenha sozinho. O modelo é
**imperativo + invalidação explícita** — o "porquê" está em
[Estado e fluxo de dados](/docs/concepts/state-and-data-flow).

## O padrão
Estado vive em **campos comuns** de um objeto seu (um ViewModel/serviço). Quando muda, **você atualiza
o widget** e chama `repaint()` — se veio de outra thread, 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();   // trabalho pesado, thread de fundo
         Component.onUI(() -> {                             // volta à paint thread
            vm.clientes = dados;
            lista.setItems(dados);                          // atualiza o widget
            Component.repaint();                            // pede novo frame
         });
      }).start();
   }
}
```

## Estado efêmero vs. de aplicação
| Tipo | Onde vive | Sobrevive à navegação? |
|---|---|---|
| **efêmero de tela** | campos da `Window` | não — some ao sair da tela |
| **de aplicação** | um singleton/serviço compartilhado | sim — persiste entre telas |

Escolha pelo escopo: o filtro de uma busca é efêmero; o usuário logado é de aplicação.

## Boas práticas
- Um **ViewModel por tela** concentra o estado e a lógica; a `Window` só liga UI ↔ VM.
- Estado compartilhado entre telas → **serviço/singleton**, não campo estático espalhado.
- Sempre volte à UI com `onUI(...)` antes de tocar em widgets a partir de thread de fundo.

## Erros comuns
- Esperar que mudar o modelo atualize a UI sozinho — **não atualiza**; chame `setX(...)` + `repaint()`.
- Guardar estado de app em campos da `Window` (perde-se ao navegar).

## Veja também
- Conceito: [Estado e fluxo de dados](/docs/concepts/state-and-data-flow) · [A paint thread](/docs/concepts/the-paint-thread)
- [Persistência com SQLite](/docs/data-and-services/storage-sqlite) · [Trabalho em background](/docs/data-and-services/background-work)
- Arquitetura de app: [best-practices](/docs/best-practices)
