State & Recomposition in Compose
In Compose, UI is a function of state. Change the state and Compose recomposes — re-running the affected composables to redraw the screen. The trick is making that state observable.
Learn State & Recomposition in Compose in our free Kotlin course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a…
Part of the free Kotlin course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
By the end you'll use remember and mutableStateOf , hoist state for reusable composables, and persist state across rotation with rememberSaveable .
What You'll Learn in This Lesson
1️⃣ Observable State with remember + mutableStateOf
A plain var won't update the UI — Compose only watches State objects. mutableStateOf makes the value observable; remember keeps it alive across recompositions. The by delegate lets you read and write it like a normal variable.
Each tap writes to count ; Compose notices the read inside the button label and recomposes just that text.
2️⃣ State Hoisting
A reusable composable should be stateless : it receives the current value and an event callback. The stateful parent owns the data. This is the state down, events up pattern.
CounterButton is now decoupled from storage — you can preview it, test it, and reuse it anywhere.
3️⃣ Surviving Rotation with rememberSaveable
Plain remember survives recomposition but not a configuration change like rotation. rememberSaveable persists the value through those too.
Your turn. Replace the TODO , then run and compare.
Bind a TextField to a String state and watch a greeting recompose as you type.
📋 Quick Reference — State
Practice quiz
What does it mean for Compose to 'recompose'?
- It rebuilds the whole app from scratch
- It re-runs composables affected by changed state to update the UI
- It recompiles the Kotlin source
- It restarts the Activity
Answer: It re-runs composables affected by changed state to update the UI. Recomposition re-runs the composables that read changed state, updating just what is needed.
Which function holds a value across recompositions?
- keep
- cache
- remember
- store
Answer: remember. remember retains a value in the composition so it survives recomposition.
Which API creates an observable state holder Compose can track?
- mutableStateOf(...)
- stateOf(...)
- observable(...)
- live(...)
Answer: mutableStateOf(...). mutableStateOf creates a MutableState that triggers recomposition when its value changes.
With 'var count by remember { mutableStateOf(0) }', how do you increment count?
- count.value++
- count.set(count + 1)
- count++
- count.update()
Answer: count++. The 'by' delegate lets you read/write count directly, so count++ works.
What problem does state hoisting solve?
- It speeds up compilation
- It moves state up so a composable becomes stateless and reusable
- It saves state to disk
- It hides state from the parent
Answer: It moves state up so a composable becomes stateless and reusable. Hoisting lifts state to a caller, making the child stateless, testable, and reusable.
A hoisted, stateless composable typically receives what two things?
- A Context and a Bundle
- A ViewModel and a Repository
- Two lambdas only
- A value and an onValueChange callback
Answer: A value and an onValueChange callback. The state-down/events-up pattern passes the current value down and an onChange event up.
Which function preserves state across configuration changes like rotation?
- rememberSaveable { ... }
- remember { ... }
- retain { ... }
- keepState { ... }
Answer: rememberSaveable { ... }. rememberSaveable survives recomposition AND configuration changes (and process recreation) via a saver.
If you use plain 'remember' and rotate the device, what happens to the value?
- It is encrypted
- It is reset to its initial value
- It is doubled
- It is saved to the database
Answer: It is reset to its initial value. Plain remember does not survive a configuration change, so the value reinitializes.
Why does 'var x = 0' (a normal variable) NOT update the UI when changed?
- Variables are immutable
- It is the wrong type
- Compose only observes State objects, not plain variables
- It needs the @State annotation
Answer: Compose only observes State objects, not plain variables. Compose recomposes only when it observes a change to a State; a plain var is invisible to it.
Where should you read a state value to make a composable recompose on change?
- Inside the composable that should update
- Only in onCreate
- In a background thread
- In the manifest
Answer: Inside the composable that should update. Reading a State inside a composable subscribes it, so that composable recomposes when the value changes.