The below two examples simply add an 'a' to a given default value. The compose_version
used is 1.0.0-alpha03
which is the latest as of today (to my knowledge).
This example is most similar to most examples I've found during my research.
Example 1
@Composable
fun MyScreen() {
val (name, setName) = remember { mutableStateOf("Ma") }
Column {
Text(text = name) // 'Ma'
Button(onClick = {
setName(name + "a") // change it to 'Maa'
}) {
Text(text = "Add an 'a'")
}
}
}
However, this isn't always practical. Say for example, the data was more complex than a single field. A class for instance, or even a Room
data class
.
Example 2
// the class to be modified
class MyThing(var name: String = "Ma");
@Composable
fun MyScreen() {
val (myThing, setMyThing) = remember { mutableStateOf(MyThing()) }
Column {
Text(text = myThing.name) // 'Ma'
Button(onClick = {
var nextMyThing = myThing
nextMyThing.name += "a" // change it to 'Maa'
setMyThing(nextMyThing)
}) {
Text(text = "Add an 'a'")
}
}
}
Of course, Example 1 works, but Example 2 does not. Is this a simple error on my part, or am I missing the larger picture about how I should go about modifying this class instance?
EDIT:
I have sort of found a way to make this work, but it seems inefficient. It does line up with how React manages state however, so maybe it is the correct way to do it.
The issue in Example 2 quite clearly is that myNextThing
is not a copy of the original myThing
, but rather a reference to it. Just like React, Jetpack Compose seems to want an entirely new object when modifying the state. This can be done in one of two ways:
- Creating a new instance of the
MyThing
class, changing what one needs to change, and then callingsetMyThing()
with the new class instance - Changing
class MyThing
todata class MyThing
and using thecopy()
function to create a new instance with the same properties. Then, change the desired property and callsetMyThing()
. This is the best way in the context of my question given that I explicitly stated that I would like to use this to modify the data on a givendata class
used by Android Room.
Example 3 (functional)
// the class to be modified
data class MyThing(var name: String = "Ma");
@Composable
fun MyScreen() {
val (myThing, setMyThing) = remember { mutableStateOf(MyThing()) }
Column {
Text(text = myThing.name) // 'Ma'
Button(onClick = {
var nextMyThing = myThing.copy() // make a copy instead of a reference
nextMyThing.name += "a" // change it to 'Maa'
setMyThing(nextMyThing)
}) {
Text(text = "Add an 'a'")
}
}
}