# Coming from Jetpack Compose

> @Composable→Component mapping and the reactive counter rewritten as field + repaint().

Source: https://crossfly.dev/docs/migrate/from-jetpack-compose — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Coming from Jetpack Compose

In Compose (declarative Kotlin) the UI **recomposes** when the observable state changes. In CrossFly you
**build once** and **mutate**. Read [the philosophy](/docs/migrate/overview) first.

## Translation table
| Jetpack Compose | CrossFly |
|---|---|
| `@Composable fun` | method that builds **once** in `onShow()` |
| `remember { mutableStateOf(...) }` + recomposition | **field** + `repaint()` (no recomposition) |
| `Column` / `Row` / `Box` | `VerticalLayout` / `HorizontalLayout` / `RelativeLayout` |
| `Modifier.weight(1f)` | `add(LAY_FILL, c)` (`-1f`) |
| `Modifier.padding(...)` | `ingap` in the style |
| `LazyColumn` | `VirtualListView` |
| `Text` | `Label` |
| `Button` | `Button` |
| `Scaffold` / `TopAppBar` | `Window` (+ `TabBar`) |
| `NavController` / `NavHost` | stack of `Window` (`show()` / `hide()`) |
| `ViewModel` + `StateFlow` | manual ViewModel + callback (no flow collection) |
| `LaunchedEffect` / coroutines | `Thread` + `Component.onUI(...)` |
| `Color(0xFF...)` | `int 0xAARRGGBB` (`UIConstants` / `ColorUtils`) |

## Before / after — the counter
```kotlin
// Compose: muda o state → recompõe sozinho
@Composable fun Contador() {
   var n by remember { mutableStateOf(0) }
   Column {
      Text("$n")
      Button(onClick = { n++ }) { Text("+") }
   }
}
```
```java
// CrossFly: keeps the reference and updates it by hand
public class Contador extends Window {
   private int n = 0;
   private Label display;
   @Override public void onShow() throws Exception {
      super.onShow();
      setLayout(new VerticalLayout());
      add(LAY_AUTO, display = new Label("0"));
      Button mais = new Button("+");
      mais.onAction(c -> { n++; display.setText(String.valueOf(n)); });   // no recomposition
      add(LAY_AUTO, mais);
   }
}
```

## The part that surprises the most
`StateFlow`/`collectAsState` have no equivalent: CrossFly **does not observe** your state. Where you would
collect a flow, store the value in a field and call `repaint()` (or a manual `observe(Runnable)` in your
ViewModel — see [app architecture](/docs/best-practices/arquitetura-de-app)).

## See also
- [State and data flow](/docs/concepts/state-and-data-flow) · [App architecture](/docs/best-practices/arquitetura-de-app)
