Search code examples
androidkotlinandroid-jetpack-composecompose-recompositionmutablestateof

Jetpack Compose TextField not updating when typing a new character


I followed this document from the developer site. I want to display the text in an OutlinedTextField from a user input, and have it survive configuration changes.

With the code below, when the user inputs the text from the keyboard, OutlinedTextField doesn't update the text.

HelloContent(name = city.name, onNameChange = { city.name = it})//Doesn't work

enter image description here

However this line of code works properly:

HelloContent(name = temp, onNameChange = { temp = it})//Work

Below is the code which I use to implement:

@Composable
fun HelloScreen() {
    var city by rememberSaveable(stateSaver = CitySaver) {
        mutableStateOf(City("Hanoi","VietNam"))
    }
    var temp by rememberSaveable {
        mutableStateOf("")
    }
    Column {
        HelloContent(name = city.name, onNameChange = { city.name = it})//Doesn't work
        HelloContent(name = temp, onNameChange = { temp = it})//Work
    }
}
@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") }
            )
        }
    }
data class City(var name: String, val country: String)
val CitySaver = run {
    val nameKey = "Name"
    val countryKey = "Country"
    mapSaver(save = {mapOf(nameKey to it.name,countryKey to it.country)},
        restore = {City(it[nameKey] as String,it[countryKey] as String)})
}

Could you help me to fix the first code block to work?

HelloContent(name = city.name, onNameChange = { city.name = it})//Doesn't work

Solution

  • The TextField will not be updated because you are only modifying city.name not the actual mutableState City object so there is nothing that tells the composer to trigger an update (re-composition).

    So modify your first HelloContent composable like this.

     HelloContent(name = city.name, onNameChange = { city = city.copy(name = it)})
    

    changing this line

    onNameChange = { city.name = it}
    

    to this

    onNameChange = { city = city.copy(name = it)}
    

    will make sure your TextField gets updated(re-composed).

    Keep in mind, invoking .copy() on data classes guarantees a new instance will be created (provided that you supplied a new value to one of its properties/fields), which is needed by Compose to trigger re-composition.