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.