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

Flutter Bloc:修改State内列表后BlocBuilder未触发调用

问题诱因

Bloc 触发组件重建的前提是emit的新状态和旧状态不相等,未触发重建的核心原因是错误使用可变状态做原地修改,具体问题点如下:

  • 直接在原有state实例上修改属性:不管是调用state.selectedFilters!.remove()删除列表元素、给state.selectedAvailability重新赋值,还是修改medicineList内元素的checked属性,都是在原state对象的内存空间上做修改,没有生成新的状态对象。
  • emit时传入的还是原state对象的引用:Bloc收到emit的状态时会对比新旧状态,如果是同一个对象实例(或者SearchState使用了Equatable做值比较,且所有属性的引用都没有变化),就会判定状态没有更新,不会通知BlocBuilder重建。
  • 列表修改逻辑存在无效代码:Dart中Iterable.map()是惰性执行的,原代码既没有消费map的返回结果,也没有将修改后的内容重新赋值给state,这段修改药品选中状态的代码本身就不会生效。
修复方案

首先要把SearchState改成不可变类,所有属性都用final修饰,禁止直接修改原state的任何属性,每次更新状态都要创建全新的state实例传入emit。
修正后的事件处理代码参考:

FutureOr<void> _removeFilter(OnFilterRemoved event, Emitter<SearchState> emit) {
  // 从旧状态拷贝需要修改的属性,生成新的对象/集合
  final newSelectedFilters = List<String>.from(state.selectedFilters ?? []);
  var newAvailability = state.selectedAvailability;
  var newMedicineList = state.medicineList;

  if (newSelectedFilters.isNotEmpty) {
    newSelectedFilters.remove(event.text);
    if (event.text == newAvailability) {
      newAvailability = '';
    } else {
      // 生成新的药品列表,不修改原列表内的对象
      newMedicineList = state.medicineList.map((element) {
        if (element.name == event.text) {
          // 有copyWith方法就用copyWith,没有就手动调用构造函数创建新实例,不要直接修改原element属性
          return element.copyWith(checked: false);
        }
        return element;
      }).toList(); // 必须调用toList()触发map逻辑执行,生成新列表
    }
  }

  // 传入全新的state实例,禁止直接传原state
  emit(SearchState(
    selectedFilters: newSelectedFilters,
    selectedAvailability: newAvailability,
    medicineList: newMedicineList,
    // 其余state属性从旧state原样拷贝,不要遗漏
  ));
}

额外注意事项:

  • 如果SearchState使用了Equatable,必须把所有属性都加入props列表,否则值对比时会出现判断错误。
  • 列表、自定义类类型的属性更新时,一定要生成新的实例,不要直接修改原实例的属性,否则就算创建了新的State对象,属性引用还是指向旧对象,Equatable还是会判定两个状态相等。
  • 不需要额外配置BlocBuilder的buildWhen参数,只要状态相等判断逻辑正确,修改后就会正常触发重建。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 17:30:48