Managing state in Jetpack Compose: remember vs derivedStateOf vs savableState
In Jetpack Compose, there are several ways to manage state, including the remember
, derivedStateOf
, and savableState
functions. Here's a detailed explanation of each function and an example of how to use them:
remember
:
remember
is a function that allows you to create a variable whose value will be remembered across recompositions.
It is typically used for a state that is local to a Composable function, such as UI state or temporary data.
The value of a remember
variable can be changed using a lambda function that is passed to it. Whenever the value of a remember
variable changes, the Composable function that uses it will be recomposed with the new value.
For example, consider a TextField
Composable function that allows the user to enter a name:
@Composable
fun NameInput(onNameChanged: (String) -> Unit) {
var name by remember { mutableStateOf("") }
TextField(
value = name,
onValueChange = {
name = it
onNameChanged(it)
},
label = { Text("Enter your name") }
)
}
In this example, we define a NameInput
Composable function that contains a TextField
that allows the user to enter a name. We use a remember
variable called name
to hold the current value of the name. Whenever the user types into the TextField
, the name
variable is updated, which triggers a recomposition of the NameInput
Composable function with the new value.
derivedStateOf
:
derivedStateOf
is a function that allows you to create a variable whose value is derived from other state variables. It takes a lambda function that defines how to derive the value of the variable based on other state variables. Whenever any of the state variables used in the lambda function changes, the derived state variable will be recomputed.
derivedStateOf
is useful when you want to compute a value based on other state variables without recomputing it every time the Composable function is recomposed.
For example, consider a Composable function that displays the sum of two numbers:
@Composable
fun AddNumbers(a: Int, b: Int) {
val sum = remember(a, b) { derivedStateOf { a + b } }
Text("Sum: $sum")
}
In this example, we define an AddNumbers
Composable function that takes two integers, a
and b
, as input. We use a derivedStateOf
variable called sum
to hold the sum of a
and b
. Whenever either a
or b
changes, the sum
variable will be recomputed with the new value, but the AddNumbers
Composable function will not be recomposed unless any other state in the function changes.
savableState
:
savableState
is a function that allows you to save and restore state across configuration changes, such as a screen rotation. It takes a lambda function that defines how to save and restore the state. The value of a savableState
variable is automatically saved and restored by the Android system. savableState
is useful when you want to preserve state across configuration changes.
For example, consider a Composable function that allows the user to enter a username and password and saves the credentials:
@Composable
fun LoginScreen() {
val savedUsername = savableState { mutableStateOf("") }
val savedPassword = savableState { mutableStateOf("") }
Column {
TextField(
value = savedUsername.value,
onValueChange = { savedUsername.value = it },
label = { Text("Username") }
)
TextField(
value = savedPassword.value,
onValueChange = { savedPassword.value = it },
label = { Text("Password") }
)
Button(onClick = { /* handle login */ }) {
Text("Log In")
}
}
}
In this example, we use savableState
to save and restore the user's entered username and password across configuration changes. We define two savableState
variables, savedUsername
and savedPassword
, that hold the current value of the user's entered username and password, respectively. Whenever the user enters a new username or password, the corresponding savableState
variable is updated.
The Android system automatically saves and restores the value of savedUsername
and savedPassword
across configuration changes, such as a screen rotation. When the Composable function is recomposed after a configuration change, the saved values are restored and used as the initial value of the corresponding TextField
s.
Here’s an another example of how to use remember
, derivedStateOf
, and savableState
in a Jetpack Compose app:
@Composable
fun CounterScreen() {
// Define a `remember` variable to hold the current count
var count by remember { mutableStateOf(0) }
// Define a `derivedStateOf` variable to hold the doubled count
val doubleCount = remember(count) { count * 2 }
// Define a `savableState` variable to hold the count across configuration changes
val savedCount = savableStateHolder { count }
// Increment the count when the button is clicked
Button(onClick = { count++ }) {
Text("Count: $count")
}
// Display the doubled count
Text("Double count: $doubleCount")
// Display the saved count
Text("Saved count: $savedCount")
}
In this example, we define a Composable function called CounterScreen
that contains three different ways of managing state: remember
, derivedStateOf
, and savableState
.
First, we define a remember
variable called count
to hold the current count. Whenever the count
variable changes, the CounterScreen
Composable function will be recomposed with the new value.
Next, we define a derivedStateOf
variable called doubleCount
to hold the doubled count. This variable depends on the count
variable, so whenever the count
variable changes, the doubleCount
variable will be recomputed.
Finally, we define a savableState
variable called savedCount
to hold the count across configuration changes. This variable is automatically saved and restored by the Android system, so the count will be preserved even if the user rotates their device.
When the user clicks the button, the count
variable is incremented, which triggers a recomposition of the CounterScreen
Composable function. The updated count, doubled count, and saved count are then displayed using the Text
Composable function.
I hope these examples and explanations helps you understand how to use remember
, derivedStateOf
, and savableState
in a Jetpack Compose app!