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

如何复制RxList数据并修改时不影响原数据?

问题解决:修改RxList副本不影响原数据的方案

问题根源

你当前的代码里 var copyList = drinks; 是浅拷贝——copyList 和原 drinks 指向同一个列表内存地址,且列表中的 Drink 对象也是同一个引用。所以修改 copyList 里元素的 isChecked 属性时,原列表的对应对象也会跟着变化。

解决方案:实现深拷贝 + 正确初始化RxList

1. 为Drink类添加深拷贝方法

给 Drink 类新增 copyWith 方法,用于生成全新的对象实例,避免引用共享:

class Drink {
  final int id;
  final String name;
  bool isChecked;

  Drink({required this.id, required this.name, required this.isChecked});

  // 生成新的Drink对象,可选择性修改属性
  Drink copyWith({int? id, String? name, bool? isChecked}) {
    return Drink(
      id: id ?? this.id,
      name: name ?? this.name,
      isChecked: isChecked ?? this.isChecked,
    );
  }
}

2. 正确初始化copyList

通过 map 遍历原列表,为每个元素生成副本,再转为RxList(适配Obx响应式):

var drinkIds = <int>[];
// 深拷贝生成独立的RxList,元素都是新的Drink实例
var copyList = drinks.map((drink) => drink.copyWith()).toList().obs;

3. 修正UI代码并处理点击事件

修复原代码中的语法错误(比如 ListTitle 应为 ListTile、itemCount 后用逗号而非分号),并通过替换元素的方式触发响应式更新:

@override
Widget build(BuildContext context) {
  return Obx(() => ListView.builder(
        shrinkWrap: true,
        physics: const NeverScrollableScrollPhysics(),
        padding: EdgeInsets.zero,
        itemCount: copyList.length,
        itemBuilder: (_, index) => ListTile(
          minLeadingWidth: 10,
          visualDensity: const VisualDensity(vertical: -4),
          contentPadding: EdgeInsets.zero,
          title: Text("${copyList[index].name}"), // 原数据里是name字段,不是title
          leading: copyList[index].isChecked
              ? const Icon(Icons.check_box_outlined, color: primaryColor)
              : const Icon(Icons.check_box_outline_blank, color: Colors.grey),
          onTap: () {
            // 生成新的Drink对象,切换isChecked状态
            final updatedDrink = copyList[index].copyWith(isChecked: !copyList[index].isChecked);
            // 替换列表中的元素,自动触发Obx更新UI
            copyList[index] = updatedDrink;

            // 更新选中ID列表
            if (updatedDrink.isChecked) {
              drinkIds.add(updatedDrink.id);
            } else {
              drinkIds.removeWhere((element) => element == updatedDrink.id);
            }
          },
        ),
      ));
}

关键说明

  • 深拷贝确保 copyList 和原 drinks 的元素是完全独立的实例,修改副本不会影响原数据。
  • 使用 copyWith 是Dart中实现对象拷贝的常用模式,灵活且易维护。
  • RxList通过替换元素触发响应式更新,比手动调用 refresh() 更符合MobX的最佳实践。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 15:50:28