Home > Software design >  Use a custom class for the value of TextField does not survive across re-composition
Use a custom class for the value of TextField does not survive across re-composition

Time:11-21

In the code below, the TextField that takes a mutableStateOf("") works as expected: The TextField shows whatever I type in.

However, if the TextField takes StrHolder.s as the value. The TextField does not show anything I type. Why is that?

class StrHolder(var s: String)

Column {
    var text by remember { mutableStateOf("") }
    TextField(
        value = text,
        onValueChange = { text = it },
    )

    var strHolder by remember {
        mutableStateOf(StrHolder(""))
    }
    Text("My text is: ${strHolder.s}")
    TextField(
        value = strHolder.s,
        onValueChange = { strHolder.s = it },
    )
}

CodePudding user response:

In order for mutableStateOf to trigger recomposition, the container value should be updated, e.g. strHolder = newValue.

There's no way how it can know you've changed one of inner values.

data class (with val-only properties) is a great tool to be used in functional programming for such cases: copying the data will save your from such mistakes:

data class StrHolder(val s: String)

var strHolder by remember {
    mutableStateOf(StrHolder(""))
}
Text("My text is: ${strHolder.s}")
TextField(
    value = strHolder.s,
    onValueChange = { strHolder = strHolder.copy(s = it) },
)

You can find more info about state in Compose in documentation, including this youtube video which explains the basic principles.

CodePudding user response:

If you want Compose to know about changes to your StrHolder.s property, you need to wrap it inside a State. Like this:

class StrHolder {
    var s by mutableStateOf("")
}
val strHolder by remember { mutableStateOf(Data()) }
TextField(
    value = strHolder.s, 
    onValueChange = { strHolder.s = it }
)
  • Related