Flutter MobX ObservableList直接修改元素不更新UI问题求助
在Flutter应用中使用MobX时遇到UI更新问题:使用ObservableList<SelectItem>渲染列表项,点击列表项时,包裹的Observer组件仅在调用.remove、.add、.clear等方法时才会更新UI;直接遍历修改列表内元素时,UI无任何变化。
当前可正常运行的代码如下:
@action void selectFuel(int index) { for (int i = 0; i < fuelSelectItemList.length; i++) { if (i == index && fuelSelectItemList[i].object.avaliable != null && fuelSelectItemList[i].object.avaliable!.compareTo(0) <= 0) { ToastService.error('Estoque indisponível no momento'); return; } } List<SelectItem<Product>> list = fuelSelectItemList.toList(); fuelSelectItemList.clear(); fuelOrderItem.fuelTankFraction = null; for (var fuelItem in list) { fuelItem.selected = false; } for (int i = 0; i < list.length; i++) { if (i == index) { list[i].selected = true; fuelOrderItem.product = list[i].object; break; } } fuelSelectItemList = ObservableList.of(list); }
不想通过创建新列表、清空原ObservableList再重新赋值的方式实现,希望直接修改列表内元素。请问此行为是否正常?是否存在直接修改元素即可触发UI更新的方法?
补充信息:MobX版本2.3.3+2,Flutter版本3.22.2
行为是否正常?
这种行为是完全正常的。ObservableList的监听逻辑仅针对列表本身的结构变化(比如添加、删除、替换元素),当你直接修改列表内元素的属性时,ObservableList并不会感知到这些内部变化——因为它只监听列表的引用和元素的位置变动,不监听元素自身的状态变更。
直接修改元素触发UI更新的方法
有两种可行方案:
1. 让SelectItem成为可观察对象
将SelectItem类用MobX的@observable标记属性,确保属性变化能被MobX追踪:
import 'package:mobx/mobx.dart'; part 'select_item.g.dart'; class SelectItem<T> = _SelectItem<T> with _$SelectItem<T>; abstract class _SelectItem<T> with Store { @observable bool selected = false; final T object; _SelectItem(this.object); }
这样,当你直接修改fuelSelectItemList[i].selected = true时,MobX会追踪到这个属性变化,触发Observer组件的UI更新。
2. 使用ObservableList的[index] = item替换元素
如果不想修改SelectItem类,可以在修改元素属性后,用替换元素的方式通知ObservableList:
@action void selectFuel(int index) { // 库存检查逻辑保留 for (int i = 0; i < fuelSelectItemList.length; i++) { if (i == index && fuelSelectItemList[i].object.avaliable != null && fuelSelectItemList[i].object.avaliable!.compareTo(0) <= 0) { ToastService.error('Estoque indisponível no momento'); return; } } fuelOrderItem.fuelTankFraction = null; // 重置所有选中状态并通知列表更新 for (int i = 0; i < fuelSelectItemList.length; i++) { final item = fuelSelectItemList[i]; if (item.selected) { item.selected = false; // 替换元素触发列表变更通知 fuelSelectItemList[i] = item; } } // 设置目标元素选中状态并通知更新 final targetItem = fuelSelectItemList[index]; targetItem.selected = true; fuelSelectItemList[index] = targetItem; fuelOrderItem.product = targetItem.object; }
这种方式通过fuelSelectItemList[i] = item触发ObservableList的变更监听,从而更新UI。
内容的提问来源于stack exchange,提问作者rafaelpadu

