Home > Back-end >  How can I see a change in the state of a map if I can't use mutable state of mutable map but I
How can I see a change in the state of a map if I can't use mutable state of mutable map but I

Time:12-12

Kotlin newbie here!

I'm trying to make a map that can be changed, but also where such a change will trigger recomposition. However, I'm hitting a conundrum and can't seem to find a way around it.

I understand that using something like this:

val someVar by remember {mutableStateOf(someMutableMap)}

is useless because it's trying to view a mutable state of objects which are themselves mutable. I understand why this doesn't work. However, I can't seem to find a way to use mutableStateOf() with a plain map because if I use a plain map, there's no way to add key / value pairs or to change the values once they're there. Makes sense, since that's what immutable means. But I need to be able to add to and change the map due to the nature of the app I'm trying to write.

I've tried:

-> Using a mutableStateOf(mutableMap), which gives me a warning about using mutable state on something that is itself mutable. This doesn't trigger recomposition, for obvious reasons.

-> Using a mutableStateOf(map), which does trigger recomposition, however, it also prevents me from adding to or changing the map, since there aren't any setters for immutable objects. This causes the function that builds the map (from a text file, but one headache at a time) to not work, along with basically everything else about the app, since the whole point is for the user to build this map.

I'm not expecting a silver-platter answer, but a little direction would be vastly appreciated. I can post code here if it will help.

CodePudding user response:

The way to do this with read-only Maps is to create new read-only Maps. You can do this using the plus and minus operators. You can use = and -= for convenience. These create new read-only maps with the modification specified relative to the original map.

val someVar by remember { mutableStateOf(mapOf("key" to 1) }

// To add something, use   and a Pair:
someVar.value = someVar.value   "some other key" to 2
// or:
someVar.value  = "some other key" to 2

// To remove something, use - and the key to remove
someVar.value = someVar.value - "key"
// or:
someVar.value -= "key"

There are more details here in the documentation. You can also add lists of pairs or maps to add a group of keys. Or you can remove lists of keys.

CodePudding user response:

You can use mutableStateMapOf to get a SnapshotStateMap which triggers recomposition when you add, remove or update existing item with new instance

val map: SnapshotStateMap<Int, String> = remember {
    mutableStateMapOf()
}

sample

@Composable
private fun MutableStateMapOfSample() {
    val map: SnapshotStateMap<Int, String> = remember {
        mutableStateMapOf()
    }

    var counter by remember {
        mutableStateOf(0)
    }

    Button(onClick = {
        map[counter] = "Value: $counter"
        counter  
    }) {
        Text("Add $counter")
    }
    
    LazyColumn(){
        items(items= map.keys.toList()) {
            Text("key: $it, value: ${map[it]}")
        }
    }
}

There is also List variant which is SnapshotStateList, mutableStateListOf, which triggers recomposition only for the updated item.

Jetpack Compose lazy column all items recomposes when a single item update

  • Related