Let's think about it for a second
Every time a Compose function is called (recomposition), it redraws the UI — but if you write a local variable like `var count = 0` inside the function, its value resets on every recomposition. Only by using `remember { mutableStateOf(0) }` does Compose keep that value alive across recompositions. Whenever a `mutableStateOf` value changes, Compose automatically redraws just the composables that use that state — State Hoisting is the pattern of not keeping state inside a child composable but instead passing it down from the parent (to make the component reusable).
Let's connect this to a real-world scenario
In a counter app, if you write `var count by remember { mutableStateOf(0) }` and do `count++` on button click, the `Text("$count")` on screen updates automatically and you'll see the number go up. Using State Hoisting, you could write `Counter(count: Int, onIncrement: () -> Unit)` where the state is passed in from the parent, letting the `Counter` composable be reused across different parents.
Let's look at an example together
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "Count: $count", fontSize = 24.sp)
Button(onClick = { count++ }) {
Text("Increment")
}
}
}Clicking the button should show 'Count: 0' → 'Count: 1' → 'Count: 2' updating live on screen.Try it in 5 minutes
Run the `Counter` composable and click the button 5 times — confirm the count updates live. Then try removing `remember` and see what happens (the value resets on every recomposition).
A quick word of caution
If you use the `by` keyword (property delegate syntax) together with `mutableStateOf`, you need to import `androidx.compose.runtime.getValue` / `setValue` — otherwise you'll hit a compile error.