You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何ViewModel中修改一个列表会同时改变另一个列表?

问题原因及解决方案

原因分析

你遇到的同步变更问题,核心是对象引用共享导致的:

  • 执行tasks.addAll(data.tasks)时,页面本地的tasks列表只是复制了ViewModel中data.tasks里TaskItem对象的引用,两个列表中的TaskItem是同一个实例,它们内部的Task对象自然也是同一个引用。
  • 虽然你的onDone扩展函数通过copy()创建了新的TaskItem和Task,但如果存在其他直接修改Task属性的操作(比如tasks[index].task.done = !tasks[index].task.done),或者onDone逻辑未被正确执行,就会通过引用关系同步修改ViewModel中data.tasks的done值。
  • 另外,如果DataModel的tasks绑定了数据库(如Room)的可观察数据源,页面修改可能触发自动同步,导致ViewModel数据被更新。

解决方案

要切断引用关联,需要对数据进行深度拷贝,确保本地列表的对象完全独立:

1. 修改数据初始化逻辑,深度拷贝TaskItem

在LaunchedEffect中,对每个TaskItem及其内部的Task进行拷贝,避免引用共享:

LaunchedEffect(key1 = Unit) {
    tasks.clear()
    val copiedTasks = data.tasks.map { taskItem ->
        // 同时拷贝TaskItem和内部的Task,彻底切断引用
        taskItem.copy(task = taskItem.task.copy())
    }
    tasks.addAll(copiedTasks)
}

2. 坚持不可变更新模式

你的onDone扩展函数已经采用了正确的“创建新对象替换旧对象”的方式,继续保持这种模式,避免直接修改现有对象的属性:

fun List<TaskItem>.onDone(index: Int): TaskItem {
    val item = this[index]
    return item.copy(task = item.task.copy(done = !item.task.done))
}

调用时通过替换列表元素完成更新:

onDone = { index ->
    tasks[index] = tasks.onDone(index)
}

3. 控制数据库同步时机(如果涉及)

如果DataModel的tasks绑定了数据库,确保只有在用户明确触发保存操作时,才将本地修改同步到数据库,避免自动同步导致的意外变更。

内容的提问来源于stack exchange,提问作者Mark Delphi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 01:11:04