android-jetpack-composejetbrains-composecompose-multiplatform

How to trigger LaunchedEffect when mutableStateList is changed?


In Jetpack/Desktop Compose I want a coroutine to run in response to changes to a SnapshotStateList.

In this example:

import androidx.compose.foundation.layout.Column
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember

@Composable
fun TestMutableList() {
    val list = remember { mutableStateListOf(1, 2, 3) }

    LaunchedEffect(list) {
        println("List was changed.")
    }

    Column {
        Button(onClick = { list[0] = 0 }) {
            Text("Change List")
        }
        list.forEach { Text(it.toString()) }
    }
}

the LaunchedEffect was run on the first composition. And the Composable recomposes when I click the button, so it knows that the SnapshotStateList<Int> changed. However, it was not run when clicking the button. I understand that this is because the key is the reference to the SnapshotStateList<Int> and that did not change.

How can I have the LaunchedEffect run every time that the list is modified?


Solution

  • With convert SnapshotStateList to ImmutableList, you can achieve to aim.

    @Composable
    fun TestMutableList() {
        val list = remember { mutableStateListOf(1, 2, 3) }
    
        LaunchedEffect(list.toList()) {
            println("List was changed.")
        }
    
        Column {
            Button(onClick = { list[0] = 0 }) {
                Text("Change List")
            }
            list.forEach { Text(it.toString()) }
        }
    }