Jetpack Compose: State Management

Durairaj S
4 min readOct 19, 2023

--

In Jetpack Compose, managing runtime UI updates is facilitated through effective state management. In this article, we’re going to learn,

What is composition?

What is State in Composable?

What is Stateless Composable?

What is State hoisting?

How to restore the state in Compose ?

What is composition?

A Composition is a tree structure of the composables that describe your UI. There are two types of compositions,

Initial Composition — Creation of a Composition by running composables the first time.

Recomposition — Re-running composables to update the Composition when data changes.

What is State in Composable?

State in an app is any value that can change over time. This is a very broad definition.

A composable that uses remember to store an object creates an internal state, making the composable stateful.

A value computed by remember is stored in the Composition during the initial composition

The stored value is returned during recomposition.

What are the ways to declare a MutableState object in a composable?

val mutableState = remember { mutableStateOf(default) } — It will return the mutable state itself.

var value by remember { mutableStateOf(default) } — By declaring this way, we can directly access the value of the mutable state.

val (value, setValue) = remember { mutableStateOf(default) } — It works like a getter and setter.

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
HelloContentWay1()
}
}
}


@Composable
fun HelloContentWay1() {
val name = remember { mutableStateOf("Durairaj") }
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Hello, ${name.value}!",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.bodyMedium
)
OutlinedTextField(
value = name.value,
onValueChange = { name.value = it },
label = {Text(text = "Name")}
)
}
}

@Composable
fun HelloContentWay2() {
Column(modifier = Modifier.padding(16.dp)) {
var name by remember { mutableStateOf("") }
if (name.isNotEmpty()) {
Text(
text = "Hello, $name!",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.bodyMedium
)
}
OutlinedTextField(
value = name,
onValueChange = { name = it },
label = { Text("Name") }
)
}
}

@Composable
fun HelloContentWay3() {
val (name, setName) = rememberSaveable { mutableStateOf("Durairaj") }
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Hello, ${name}!",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.bodyMedium
)
OutlinedTextField(
value = name,
onValueChange = { setName(it) },
label = { Text(text = "Name") }
)
}
}

What is Stateless Composable?

A composable that doesn’t hold any state. An easy way to achieve stateless is by using state hoisting.

fun HelloContentStateLess() {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Hello!",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.bodyMedium
)
OutlinedTextField(
value = "",
onValueChange = ,
label = { Text( text = "Durairaj") }
)
}
}

What is State hoisting?

State hoisting in Compose is a pattern of moving state to a caller composable to make a callee composable stateless.

The general pattern for state hoisting in Jetpack Compose is to replace the state variable with two parameters:

  • value: T: the current value to display
  • onValueChange: (T) -> Unit: an event that requests the value to change, where T is the proposed new value

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
HelloScreen()
}
}
}

@Composable
fun HelloScreen() {
var name by rememberSaveable { mutableStateOf("Durairaj") }
Column {
HelloContentSH(currentValue = name, onValueChange = { name = it })
HelloContentSH(label = "Name (Read Only field)", currentValue = "Durairaj") {}
}
}


@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun HelloContent(label: String = "Name", currentValue: String, onValueChange: (String) -> Unit ) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Hello, ${currentValue}!",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.bodyMedium
)
OutlinedTextField(
value = currentValue,
onValueChange = onValueChange,
label = { Text( text = label) }
)
}
}

Now, HelloScreen() is the caller composable that passes the value and callback function to the callee. On value change, the mutable state updates and the UI recomposes with the new value.

How to restore the state in Compose?

The rememberSaveable API behaves similarly to remember because it retains state across recompositions and across activity or process recreation using the saved instance state mechanism. For example, this happens, when the screen is rotated.

@Composable
fun HelloContentRestore() {
val name = rememberSaveable { mutableStateOf("Durairaj") }
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Hello, ${name.value}!",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.bodyMedium
)
OutlinedTextField(
value = name.value,
onValueChange = { name.value = it },
label = {Text(text = "Name")}
)
}
}

That’s it, folks. Happy learning.

--

--

No responses yet