# 管理状态

> 没有响应式绑定 —— 状态存于字段/ViewModel,View 手动将状态→组件翻译。

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

# 7. 管理状态

> **你将学到:** CrossFly 的状态模型 —— 这里是来自 Flutter/React 的人需要**忘却重学**之处。**前置条件:** [处理输入](/docs/learn/handling-input)。

## 完整示例(复制、粘贴、运行)
一个轻量的 ViewModel(`TarefaVM`),带手动的 `observe(Runnable)`(没有响应式绑定):当状态变化时 View 重新填充组件。一个按钮添加任务,列表随之重新渲染。可直接编译运行。
```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);   // 状态变化时重新填充
      renderizarLista();
   }

   private void renderizarLista()
   {
      listaBox.removeAll();
      for (Tarefa t : vm.tarefas) listaBox.add(LAY_AUTO, new Label(t.titulo));
      listaBox.setValidLayout(false);      // 尺寸已改变
      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();                             // 通知 View（在 paint thread 上）
   }
}
```
> 下面的片段只展示**核心部分**(放在 `onShow()` 里的内容)。要运行,请把它们放进上面的 `MainWindow` 骨架里。

## 没有响应式绑定
修改模型**不会**自动更新 UI。状态存活于字段(或一个轻量的 **ViewModel**)中,而 View **手动将状态 → 组件翻译**,调用 `repaint()`(如果尺寸变化了,还要调用 `setValidLayout(false)`)。

## 一个带 `observe` 的轻量 ViewModel
```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();                    // 通知 View（在 paint thread 上）
   }
}
```

## View 做出反应
```java
@Override public void onShow() throws Exception {
   super.onShow();
   // … 构建 UI …
   vm.observe(this::renderizarLista);   // 状态变化时重新填充组件
   vm.carregar();                       // 触发加载（在后台 — 下一章）
}

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();
}
```
> 规则:修改和通知**始终在绘制线程上**进行。如果数据来自后台,在改动 View 读取的状态之前,先进入 `Component.onUI(...)`(见下一章)。

## 本步骤所构建的
**`TarefaVM`** 以及在状态变化时会重新渲染的界面。

## 回顾
无响应式:状态存于字段/ViewModel;View 用 `repaint()` 将状态→组件翻译;一个手动的 `observe(Runnable)` 替代了绑定。

## 下一步
→ [加载数据](/docs/learn/loading-data)

## 另见
- 概念:[状态与数据流](/docs/concepts/state-and-data-flow) · [应用架构](/docs/best-practices/arquitetura-de-app)
