Understanding Stateful & Stateless in Jetpack Compose
Today I will briefly explain what Stateful & Stateless is in Jetpack Compose through code snippets based on my personal understanding when reading State and Jetpack Compose.
Stateful
Based on Stateful versus stateless explanation. Stateful is when Composable create, holds and modifies its own State. Consider the following code:
@Composable
fun Greeting() {
val context = LocalContext.current
var isExpanded by remember { mutableStateOf(false) }
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text(
modifier = Modifier.weight(1f),
text = context.getString(R.string.lorem),
maxLines = if (!isExpanded) 4 else Int.MAX_VALUE
)
IconButton(
modifier = Modifier.align(Alignment.CenterVertically),
onClick = { isExpanded = !isExpanded }) {
Image(
imageVector = if (isExpanded) Icons.Filled.KeyboardArrowDown else Icons.Filled.KeyboardArrowUp,
contentDescription = ""
)
}
}
}
Greeting
is a Stateful because it create, holds and modifies its own State and in this example isExpanded
is the State
Stateful is useful when we don’t need to control the State of a Composable and we can use it without having to manage the state themselves.
However, according to the Stateful versus stateless explanation, the weakness of Stateful is that it tends to be less reusable and difficult to test.
Stateless
Based on Stateful vs stateless explanation. Stateless is when Composable does not create, holds and modify its own State. Consider the following code:
@Composable
fun HelloScreen() {
var name by rememberSaveable { mutableStateOf("") }
HelloContent(name = name, onNameChange = { name = it })
}
@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Hello, $name",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5
)
OutlinedTextField(
value = name,
onValueChange = onNameChange,
label = { Text("Name") }
)
}
}
HelloContent
is an example of Stateless because it does not create, holds and modify its own State. Rather it only receive & hoist the State and this pattern is called State hoisting.
As you develop reusable Composables, you often want to expose both a Stateful and a Stateless version of the same composable. The Stateful version is convenient for callers that don’t care about the state, and the Stateless version is necessary for callers that need to control or hoist the State.