Elye
Elye

Reputation: 60341

How to update the original list when SnapshotStateList is updated

I have a todo list in Jetpack Compose displayed in LazyColumn.

data class TodoItem(val id: Int, val title: String, var urgent: Boolean = false)

val todoList = listOf(
    TodoItem(0, "My First Task", true),
    TodoItem(1, "My Second Task", true),
    TodoItem(2, "My Third Task"),
)

@Composable
fun Greeting(name: String) {
    val todoListState = remember {
        todoList.toMutableStateList()
    }
    LazyColumn(modifier = Modifier.fillMaxHeight()) {
        items(items = todoListState, itemContent = { item ->
            Row(modifier = Modifier.fillMaxWidth(),
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text(
                    modifier = Modifier.weight(1f).padding(8.dp),
                    text = item.title)
                Checkbox(
                    checked = item.urgent,
                    onCheckedChange = {
                        val index = todoListState.indexOf(item)
                        todoListState[index] = todoListState[index].copy(urgent = it)
                        Log.d("Track", "$todoList")
                    }
                )
            }
        })
    }
}

The first time it is

[TodoItem(id=0, title=My First Task, urgent=true), 
 TodoItem(id=1, title=My Second Task, urgent=true), 
 TodoItem(id=2, title=My Third Task, urgent=false)]

After I updated first to false, then it's false

[TodoItem(id=0, title=My First Task, urgent=false), 
 TodoItem(id=1, title=My Second Task, urgent=true), 
 TodoItem(id=2, title=My Third Task, urgent=false)]

When I update first to true back, the todoItem no longer change and remain as After I updated first to false, then it's false

[TodoItem(id=0, title=My First Task, urgent=false), 
 TodoItem(id=1, title=My Second Task, urgent=true), 
 TodoItem(id=2, title=My Third Task, urgent=false)]

I check the todoListState (the SnapshotStateList), and it's no longer in sync with todoList. What causes that? How to fix it?

Updated

To fix it, I can use

                Checkbox(
                    checked = item.urgent,
                    onCheckedChange = {
                        val index = todoListState.indexOf(item)
                        todoListState[index] = todoListState[index].copy(urgent = it)
                        todoList[index].urgent = it
                        Log.d("Track", "$todoList")
                    }
                )

But that means I have to change 2 item at the same time. How can I just change one, and get both updated?

Upvotes: 1

Views: 7609

Answers (2)

Thracian
Thracian

Reputation: 67443

The reason it's not updated because toMutableStateList adds items of list

fun <T> Collection<T>.toMutableStateList() = SnapshotStateList<T>().also { it.addAll(this) }

You should create one SnapshotStateList and add, remove and update items on this list. The approach you use is not correct.

If you wish to create a SnapshotStateList with initial items you can use

Edit

I missed SnapShotStateList doesn't have an add function.

SnapShotState can be used with addAll or you need to add them as items without

 val todoList = remember {
       mutableStateListOf().apply {
        add(TodoItem(id=0, title="My First Task", urgent=true))
        add(TodoItem(id=1, title="My Second Task", urgent=true))
        ...
    }
 }

Should instead be as in @Elye's answer or as

val todoList = mutableStateListOf().apply {
        addAll(initialList)
 }

or if list is a parameter of a function or need to retrieve items from a list is required use addAll or toMutableStateList but use only SnapshotStateList for updating items.

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

Upvotes: 6

Elye
Elye

Reputation: 60341

I use

val todoList = mutableStateListOf(
    TodoItem(0, "My First Task", true),
    TodoItem(1, "My Second Task", true),
    TodoItem(2, "My Third Task"),
)

UPDATED

I learn this answer, by evolving what was proposed by @Thracian in https://stackoverflow.com/a/74968199/3286489.

The answer provided by @Thracian is not compilable as shonw in the

enter image description here

So I made the above answer from it and put it here as a reference to a compilable answer.

Upvotes: 1

Related Questions