How to trigger LaunchedEffect when mutableStateList is changed?
Asked Answered
C

3

5

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?

Carnation answered 29/9, 2022 at 9:50 Comment(1)
You want to look at snapshotFlow, but again pay attention to the fact that the list object itself never changes, so don't return that from the snapshotFlow directly: stackoverflow.com/questions/70404434Dip
C
5

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()) }
    }
}
Chrystalchryste answered 30/9, 2022 at 11:23 Comment(1)
i don't know where you got this stuff but works man, thank you, can you share the reference link where got to know .toList() worksTetter
U
5

I had the same problem and got it working using the list size instead of the list itself.

Like this:

val list = remember { mutableStateListOf(1, 2, 3) }

LaunchedEffect(list.size) {
    println("List was changed.")
}
Unknow answered 16/11, 2022 at 22:0 Comment(0)
E
1

You can update an integer for anytime you change list so it will trigger when that value is changed

val list = remember { mutableStateListOf(1, 2, 3) }

var changeIndex by remember {
    mutableStateOf(0)
}

LaunchedEffect(list.size, changeIndex) {
    // add an if here if you don't want to trigger when changeIndex is 0
    println("List was changed.")
}

Column {
    Button(onClick = { list[0] = 0 }) {
        changeIndex ++
        Text("Change List")
    }
    list.forEach { Text(it.toString()) }
}
Exurbia answered 29/9, 2022 at 9:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.