State in Compose.

Compose UI reflects state. When state changes, the UI updates. This is the core of declarative UI. Today we understand how state works in Compose and how to manage it effectively.

In declarative UI, you describe what the UI should look like for a given state.

State is data that can change. A counter value. A text field's content. Whether a checkbox is checked.

When state changes, the UI rebuilds. Compose calls your composable functions again with the new state. They produce new UI.

You do not manually update the UI. You change the state. Compose handles the update.

This is powerful. The UI is always consistent with the state. No bugs from forgetting to update some part.

Consider this: var count equals 0 in a composable. Button increments count. Text shows count.

This does not work. The variable is recreated every time the composable runs. Changes are lost.

Composables can run many times. Any time state changes, Compose might call your composable again. Local variables do not survive.

You need a way to keep state across recompositions. Local variables are not enough.

remember preserves state across recompositions.

val count equals remember brace mutableStateOf 0 close brace.

remember tells Compose: keep this value. Do not recreate it on recomposition.

mutableStateOf creates observable state. When it changes, composables that read it recompose.

Together, remember plus mutableStateOf is how you hold state in composables.

The value survives recomposition. It does not survive configuration changes or process death.

mutableStateOf creates a state holder.

It wraps a value. You can read and write through it.

val state equals mutableStateOf "initial". state dot value gives you the string. state dot value equals "new" changes it.

When you write, Compose knows. It schedules recomposition for any composable that read this state.

This is reactivity. Change the state, UI updates automatically.

Writing state dot value everywhere is verbose. Kotlin property delegation helps.

var count by remember brace mutableStateOf 0 close brace.

Now count acts like a regular variable. count gives you the value. count equals 5 changes it.

Under the hood, delegation calls value getter and setter. But your code is cleaner.

Import getValue and setValue from compose runtime for this syntax.

Recomposition is when Compose calls your composables again.

It happens when state changes. Compose detects the change and reruns affected composables.

Compose is smart. It only recomposes composables that read the changed state. Not the entire UI.

Composables should be fast. They run often. Do not do heavy work inside composables.

Side effects in composables can cause problems. Remember: composables might run many times.

State hoisting lifts state up to a caller.

A composable receives state and an event callback. It does not own the state.

at Composable fun Counter count Int onIncrement arrow Unit. The composable displays count. It calls onIncrement when clicked.

The parent owns the state. It passes count and handles onIncrement.

Why hoist? Reusability. Testability. The composable is stateless. It works with any state source.

Stateless composables are easier to preview, test, and reuse.

A stateful composable manages its own state.

at Composable fun Counter brace var count by remember... Text count Button increment close brace.

It is self-contained. Easy to use. But harder to test and reuse.

A stateless composable receives state from outside.

at Composable fun Counter count Int onIncrement brace... close brace.

It is controlled by the caller. More flexible. More testable.

Best practice: make composables stateless when possible. Hoist state to the level that needs it.

A form with text input.

The parent screen owns the state. var name by remember mutableStateOf empty.

The input receives name and onNameChange.

at Composable fun NameInput name String onNameChange arrow Unit brace OutlinedTextField value equals name onValueChange equals onNameChange close brace.

The parent composes the input: NameInput name onNameChange equals brace name equals it close brace.

State is hoisted. Input is stateless. Easy to preview, test, and reuse.

Let us summarize.

State drives Compose UI. When state changes, UI recomposes.

remember preserves state across recompositions.

mutableStateOf creates observable state that triggers recomposition.

State hoisting lifts state to callers for better reusability.

Stateless composables are easier to test and reuse than stateful ones.

Design composables to be stateless where practical. Hoist state to the appropriate level.