Flutter中使用MobX @observable与Observer时UI不更新的问题排查
问题分析与解决方案
核心错误点
1. 组件构造函数参数绑定错误
QuizzOptionButtons的构造函数中,isSelected参数未正确绑定到组件成员变量:
// 错误写法 required widget.isSelected // 正确写法应该是 required this.isSelected
这个错误导致组件无法接收外部传入的选中状态,无论MobX状态如何变化,组件的isSelected始终未被正确赋值,UI自然不会更新。
2. onSelect方法逻辑混乱
- 先执行
optionsSelecteds[index] = !optionsSelecteds[index]切换当前选项状态,随后立刻通过循环强制将当前选项设为选中、其他选项设为未选中,完全覆盖了之前的操作,逻辑矛盾。 - 未区分单选和多选场景,不管是否开启多选,都执行单选逻辑,导致多选功能完全失效。
3. 冗余方法调用
页面中同时调用ChangeSelectedOptions和onSelect,但onSelect内部已经处理了selectedOption的赋值,前者属于冗余操作。
修正后的代码
1. 修复QuizzOptionButtons构造函数
class QuizzOptionButtons extends StatefulWidget { final String title; final bool isSelected; final List<dynamic>? options; final int index; final VoidCallback onTap; final bool isMultipleChoice; const QuizzOptionButtons({ Key? key, required this.title, required this.isSelected, // 修正为this.isSelected required this.onTap, this.isMultipleChoice = false, required this.options, required this.index, }) : super(key: key); // ... 其余代码不变 }
2. 重构onSelect方法,区分单选/多选逻辑
@action void onSelect(int index, List<dynamic> options, bool isMultipleChoice) { if (isMultipleChoice) { // 多选:切换当前选项的选中状态 optionsSelecteds[index] = !optionsSelecteds[index]; labelSelecteds[index] = optionsSelecteds[index] ? options[index] : ''; } else { // 单选:仅选中当前选项,其余全部取消 for (int i = 0; i < optionsSelecteds.length; i++) { if (i == index) { optionsSelecteds[i] = true; labelSelecteds[i] = options[index]; selectedOption = options[index]; } else { optionsSelecteds[i] = false; labelSelecteds[i] = ''; } } } }
3. 简化页面中的onTap逻辑
移除冗余的ChangeSelectedOptions调用:
onTap: () { controller.onSelect(index, widget.options!, widget.isMultipleChoice!); debugPrint(widget.options![index]); debugPrint(controller.optionsSelecteds.toString()); debugPrint(controller.labelSelecteds.toString()); },
4. 确保状态初始化时机(可选)
在页面的State类中,确保问卷选项变化时重新初始化选中状态列表:
@override void initState() { super.initState(); controller.isSelectedList(widget.options!, widget.isMultipleChoice!); } @override void didUpdateWidget(covariant YourPageWidget oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.options != widget.options) { controller.isSelectedList(widget.options!, widget.isMultipleChoice!); } }
验证效果
修正后,点击选项时:
- 单选模式下,只会选中当前选项,其他选项自动取消选中
- 多选模式下,可自由切换单个选项的选中状态
- UI会根据MobX中的
optionsSelecteds状态实时更新
内容的提问来源于stack exchange,提问作者Yuri Trindade
相关产品推荐
相关产品推荐

