I've got code like this:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TestsTheme {
var myvalue = remember{ mutableStateOf(4)}
Row() {
CustomText(myvalue = myvalue)
CustomButton(myvalue = myvalue)
}
}
}
}
}
@Composable
fun CustomButton(myvalue: MutableState<Int>) {
Button(onClick = {myvalue.value }) {
}
}
@Composable
fun CustomText(myvalue: MutableState<Int>) {
Text("${myvalue.value}")
}
When I click CustomButton, CustomText recomposes and changes it's value (and it is ok), but if I replace myvalue with an object of some class it does'nt work
How do I make the CustomText recompose if myvalue is now an instance of TestClass and it changes in the code below?
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TestsTheme {
var myvalue = remember{ mutableStateOf(TestClass(4))}
Row() {
CustomText(myvalue = myvalue)
CustomButton(myvalue = myvalue)
}
}
}
}
}
@Composable
fun CustomButton(myvalue: MutableState<TestClass>) {
Button(onClick = {myvalue.value.a }) {
}
}
@Composable
fun CustomText(myvalue: MutableState<TestClass>) {
Text("${myvalue.value.a}")
}
data class TestClass(var a: Int) {
}
CodePudding user response:
Compose can only understand that it should recompose if you set the value of a State
object. In your example myvalue.value
is really just short for myvalue.value = myvalue.value.inc()
, so what triggers the recomposition is calling the state.value
setter.
If you just mutate a property of the object held by a state, you are not calling the setter and no recomposition happens.
So you have 2 options to solve this:
- Make
TestClass
immutable and update theState
with a new object
data class TestClass(val a: Int) { // << changed var to val
}
@Composable
fun CustomButton(myvalue: MutableState<TestClass>) {
Button(onClick = {
val current = myvalue.value
myvalue.value = current.copy(a = current.a 1)
}) {
}
}
This is not really nice to read but doesn't require TestClass
to contain any compose-specific code.
- Make
TestClass
a state holder
class TestClass(a: Int) {
var a by mutableStateOf(a)
}
@Composable
fun Parent(){
val myvalue = remember{ TestClass(4) } // no mutableStateOf, state is managed inside the object
CustomButton(myvalue = myvalue)
}
@Composable
fun CustomButton(myvalue: TestClass) {
Button(onClick = { myvalue.a }) {
}
}