State Hoisting in Jetpack Compose – Zustand richtig herausziehen
Wer in Compose Zustand direkt in die UI packt, bekommt schwer testbare Composables. Mit State Hoisting trennst du Anzeige und Zustand sauber – wiederverwendbar und testbar.
In Jetpack Compose merkt sich ein Composable seinen Zustand mit remember und mutableStateOf. Das ist bequem – aber wenn der Zustand *im* Composable steckt, kannst du es weder wiederverwenden noch vernünftig testen. Die Lösung heißt State Hoisting: den Zustand nach oben ziehen und ihn als Parameter reinreichen.
Vorher: Zustand klebt in der UI
import androidx.compose.runtime.*
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("Klicks: $count")
}
}Das funktioniert, ist aber fest verdrahtet: Der Button *besitzt* seinen Zustand.
Nachher: State Hoisting
Du teilst in zwei Composables – ein zustandsloses (nur Anzeige) und ein zustandsbehaftetes (hält den State):
import androidx.compose.runtime.*
// Zustandslos: bekommt Wert + Callback rein → wiederverwendbar & testbar
@Composable
fun CounterButton(count: Int, onIncrement: () -> Unit) {
Button(onClick = onIncrement) {
Text("Klicks: $count")
}
}
// Zustandsbehaftet: hält den State und reicht ihn nach unten
@Composable
fun CounterScreen() {
var count by remember { mutableStateOf(0) }
CounterButton(count = count, onIncrement = { count++ })
}Die Faustregel lautet „state down, events up": Der Wert fließt als Parameter nach unten, Ereignisse (Klicks) als Lambda-Callback nach oben. Das zustandslose CounterButton lässt sich jetzt in der Vorschau mit festen Werten anzeigen und im Test ohne echten State prüfen.
Warum das wichtig ist
- Wiederverwendbar: Dasselbe
CounterButtonfunktioniert überall, egal woher der Wert kommt. - Testbar: Du übergibst einfach einen festen
count– kein Framework-Zauber nötig. - Single Source of Truth: Der Zustand lebt an *einer* Stelle, nicht verstreut in der UI.
Bei echten Apps wandert der Zustand oft noch weiter hoch – ins ViewModel. Aber das Prinzip bleibt gleich.
Brauchst du eine saubere Android-App in Kotlin & Compose? Melde dich bei mir.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
derivedStateOf – abgeleiteten Zustand berechnen, ohne Recompositions zu verschwenden
Wenn du aus einem sich schnell ändernden State einen selten wechselnden Wert ableitest (z. B. "Nach-oben-Button ab Item 5"), verhindert derivedStateOf, dass dein UI bei jedem Scroll-Pixel neu zeichnet.
remember vs. rememberSaveable – Zustand, der die Drehung übersteht
remember hält Zustand über Recompositions, verliert ihn aber bei Konfigurationsänderungen wie der Bildschirmdrehung. rememberSaveable rettet einfache Werte automatisch über den Bundle-Mechanismus.
DisposableEffect in Compose – aufräumen, wenn ein Composable verschwindet
Immer wenn du in Compose etwas registrierst – einen Listener, einen Sensor, einen Callback – musst du es auch wieder abmelden. Genau dafür gibt es DisposableEffect mit seinem onDispose-Block.