# Gestionando el estado

> Sin binding reactivo — estado en campos/ViewModel, la View traduce estado→componentes a mano.

Source: https://crossfly.dev/es/docs/learn/managing-state — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# 7. Gestionando el estado

> **Lo que vas a aprender:** el modelo de estado de CrossFly — donde quien viene de Flutter/React necesita
> **desaprender**. **Prerrequisitos:** [Manejando la entrada](/docs/learn/handling-input).

## Ejemplo completo (copiar, pegar y ejecutar)
Una ViewModel liviana (`TarefaVM`) con `observe(Runnable)` manual (no hay binding reactivo): la View re-puebla
los componentes cuando el estado cambia. Un botón agrega tareas y la lista se re-renderiza. Compila tal cual.
```java
package com.exemplo;

import java.util.*;
import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;

public class MainWindow extends Window
{
   private final TarefaVM vm = new TarefaVM();
   private final Component listaBox = new Component();
   private int contador = 1;

   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      Button add = new Button("Adicionar tarefa");
      add.onAction(c -> vm.adicionar(new Tarefa("Tarefa " + (contador++))));
      add(LAY_AUTO, add);

      listaBox.setLayout(new VerticalLayout());
      add(LAY_FILL, listaBox);

      vm.observe(this::renderizarLista);   // re-puebla cuando el estado cambia
      renderizarLista();
   }

   private void renderizarLista()
   {
      listaBox.removeAll();
      for (Tarefa t : vm.tarefas) listaBox.add(LAY_AUTO, new Label(t.titulo));
      listaBox.setValidLayout(false);      // el tamaño cambió
      Component.repaint();
   }
}

class Tarefa
{
   final String titulo;
   Tarefa(String titulo) { this.titulo = titulo; }
}

class TarefaVM
{
   private Runnable onChange;
   public List<Tarefa> tarefas = new ArrayList<>();

   public void observe(Runnable r) { this.onChange = r; }
   private void mudou() { if (onChange != null) onChange.run(); }

   public void adicionar(Tarefa t)
   {
      var novo = new ArrayList<>(tarefas); novo.add(t);
      tarefas = novo;
      mudou();                             // notifica a la View (en el paint thread)
   }
}
```
> Los fragmentos de abajo muestran **solo el núcleo** (lo que va dentro de `onShow()`). Para ejecutar, colócalos en el esqueleto `MainWindow` de arriba.

## No hay binding reactivo
Cambiar el modelo **no** actualiza la UI solo. El estado vive en campos (o en una **ViewModel** liviana), y la
View **traduce estado → componentes manualmente**, llamando a `repaint()` (y `setValidLayout(false)` si el
tamaño cambió).

## Una ViewModel liviana con `observe`
```java
public class TarefaVM {
   private Runnable onChange;
   public List<Tarefa> tarefas = List.of();
   public void observe(Runnable r) { this.onChange = r; }
   private void mudou() { if (onChange != null) onChange.run(); }

   public void adicionar(Tarefa t) {
      var novo = new ArrayList<>(tarefas); novo.add(t);
      tarefas = novo;
      mudou();                    // notifica a la View (en el paint thread)
   }
}
```

## La View reacciona
```java
@Override public void onShow() throws Exception {
   super.onShow();
   // … monta UI …
   vm.observe(this::renderizarLista);   // re-puebla los componentes cuando el estado cambia
   vm.carregar();                       // dispara la carga (en background — próximo capítulo)
}

private void renderizarLista() {
   listaBox.removeAll();
   for (Tarefa t : vm.tarefas) { CardTarefa card = new CardTarefa(); listaBox.add(LAY_AUTO, card); card.bind(t); }
   listaBox.setValidLayout(false);
   Component.repaint();
}
```
> Regla: las mutaciones y notificaciones **siempre en la paint thread**. Si el dato vino de fondo, entra en
> `Component.onUI(...)` antes de tocar el estado que la View lee (ver próximo capítulo).

## Construyes en este paso
La **`TarefaVM`** con la pantalla re-renderizándose cuando el estado cambia.

## Recapitulando
Sin reactivo: estado en campos/ViewModel; la View traduce estado→componentes con `repaint()`; un
`observe(Runnable)` manual sustituye el binding.

## Próximos pasos
→ [Cargando datos](/docs/learn/loading-data)

## Ver también
- Concepto: [Estado y flujo de datos](/docs/concepts/state-and-data-flow) · [Arquitectura de app](/docs/best-practices/arquitetura-de-app)
