Flutter中BlocSelector未触发更新问题求助
核心问题
BlocSelector 是通过对比选择器返回的前后值是否相等来决定是否触发 builder 重建的,默认使用 == 做引用比较。你的代码里存在两个关键问题:
状态更新时未创建新的 List 实例
如果你的 Bloc 在处理时间到期事件时,只是直接修改原有objectsHistory列表的内容(比如调用add/remove),然后 emit 一个包含相同 List 引用的新状态,那么前后两次状态中的objectsHistory是同一个引用,==比较会判定为相等,BlocSelector 就不会触发重建。泛型类型笔误
你的 Widget 代码里 BlocSelector 的泛型写的是Bloctate,但状态类实际是BlocState,这个类型不匹配也可能导致状态订阅异常。
修复步骤
1. 确保状态不可变,每次更新生成新 List
修改 Bloc 中的状态更新逻辑,每次需要更新 objectsHistory 时,创建一个新的 List 实例,而不是修改原有列表:
// Bloc 中的事件处理逻辑示例 on<MoveToHistoryEvent>((event, emit) { // 生成新列表,添加新元素或移除旧元素 final newHistory = List<SomeObject>.from(state.objectsHistory) ..add(event.expiredObject); // emit 包含新列表的全新状态 emit(BlocState(newHistory)); });
或者用展开运算符简化:
emit(BlocState([...state.objectsHistory, event.expiredObject]));
2. 修正泛型类型错误
把 Widget 代码里的 Bloctate 改成正确的 BlocState:
@override Widget build(BuildContext context) { return BlocSelector<MyBloc, BlocState, List<MyObject>>( selector: (state) => state.objectsHistory, builder: (context, objectsHistory) { print(objectsHistory.length); return Text('历史记录数量:${objectsHistory.length}'); }, ); }
可选:自定义相等校验(不推荐,仅作补充)
如果因特殊原因无法创建新 List,可以在 BlocSelector 中自定义相等校验逻辑,对比列表内容而非引用:
import 'package:flutter/foundation.dart'; // 引入listEquals BlocSelector<MyBloc, BlocState, List<MyObject>>( selector: (state) => state.objectsHistory, equalityCheck: (previous, current) => listEquals(previous, current), builder: (context, objectsHistory) { print(objectsHistory.length); return Text('历史记录数量:${objectsHistory.length}'); }, )
注意:这种方式不如创建新列表高效,因为需要遍历列表对比内容,不符合 Bloc 状态不可变的设计原则,优先推荐第一种方案。
为什么 BlocBuilder 能正常工作?
BlocBuilder 不做值对比,只要 Bloc emit 新状态(哪怕状态内容和之前一致),它都会触发重建。而 BlocSelector 是“选择性重建”,只有当选择器返回的值发生变化时才会更新,所以会出现两者表现不同的情况。
内容的提问来源于stack exchange,提问作者Preem Palver2

