Flutter Bloc状态变更后UI不更新,需热重载才生效的问题
Flutter Bloc GridView不刷新问题解决方案
问题根源
你的Bloc中维护了一个可变的noteModel列表,每次添加新笔记后,直接将这个列表的原引用传递给Notes状态并emit。由于Equatable对比props中的列表时是对比引用而非内容,即使列表内容改变,只要引用不变,Bloc会判定前后状态相等,不会触发BlocBuilder重建UI。
另外,若NoteModel未继承Equatable,也会影响Equatable对列表内容的判断(虽非本次问题核心,但建议补充)。
修复方案
1. 每次emit时创建新列表副本
修改Bloc中的SavedNote事件处理逻辑,每次emit新状态时传递列表的新副本,而非原引用:
class NoteBloc extends Bloc<NoteEvent, NoteState> { NoteBloc() : super(const Notes([])) { final List<NoteModel> noteModel = []; on<SavedNote>((event, emit) async { noteModel.add(NoteModel(noteModel.length + 1, event.time, event.message)); await Future.delayed(const Duration(seconds: 1)); // 创建新列表副本,确保引用不同 emit(Notes(List.from(noteModel))); // 也可使用扩展运算符:emit(Notes([...noteModel])); }); } }
2. 符合Bloc规范的写法:状态内维护列表(推荐)
Bloc设计原则为状态不可变,应将列表维护在状态中,而非Bloc类的成员变量。每次更新基于旧状态创建新状态:
class NoteBloc extends Bloc<NoteEvent, NoteState> { NoteBloc() : super(const Notes([])) { on<SavedNote>((event, emit) async { await Future.delayed(const Duration(seconds: 1)); if (state is Notes) { final currentNotes = (state as Notes).noteList; final newNotes = List.from(currentNotes) ..add(NoteModel(currentNotes.length + 1, event.time, event.message)); emit(Notes(newNotes)); } }); } }
3. 确保NoteModel继承Equatable
让Equatable能正确对比列表元素,NoteModel需继承Equatable:
class NoteModel extends Equatable { final int id; final DateTime time; final String message; const NoteModel(this.id, this.time, this.message); @override List<Object?> get props => [id, time, message]; }
额外检查
确认BlocBuilder监听的是正确的Bloc实例,你的代码中弹窗使用当前上下文的Bloc,这部分逻辑是正确的。
修改后,每次添加新笔记时会emit带有新列表引用的Notes状态,Equatable能检测到状态变化,BlocBuilder会立即重建GridView,显示新的笔记卡片。
内容的提问来源于stack exchange,提问作者Tahiru Agbanwa
相关产品推荐
相关产品推荐

