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.
Mini-Challenge: A Live Greeter
Bind a TextField to a String state and watch a greeting recompose as you type.
Common Errors (and the fix)
- Using a plain var — A normal variable won't recompose the UI. Wrap it in mutableStateOf .
- Forgetting remember — Without it, the state resets to its initial value on every recomposition.
- Missing by imports — The by delegate needs getValue / setValue imports; otherwise use .value .
- Expecting rotation to keep remember — Use rememberSaveable for values that must survive configuration changes.
Pro Tips
- 💡 Single source of truth: hoist state so only one composable owns it.
- 💡 Keep composables stateless where you can: they're easier to preview and test.
- 💡 Reach for rememberSaveable for anything a user would be annoyed to lose on rotation.
📋 Quick Reference — State
Concept
Compose API
Observable state
remember { mutableStateOf(0) }
Read/write directly
var n by remember { ... }
Survive rotation
rememberSaveable { mutableStateOf(0) }
Hoisting (down)
fun C(value: Int, ...)
Hoisting (up)
onValueChange: (Int) -> Unit
Frequently Asked Questions
🎉 Lesson Complete!
- ✅ Recomposition re-runs composables that read changed state
- ✅ mutableStateOf makes a value observable
- ✅ remember keeps state across recompositions
- ✅ Hoisting yields stateless, reusable composables
- ✅ rememberSaveable survives rotation
- ✅ Next lesson: Compose Layouts, Modifiers & Lists
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.
Continue this course
- Previous: Jetpack Compose Basics
- Next: Compose Layouts, Modifiers & Lists