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

使用Equatable后Bloc emit属性不同的同状态仍不触发Builder

问题原因及解决方案

核心问题

Bloc不触发重建的根本原因是新旧状态的reports列表引用相同,Equatable比较时会判定状态未发生变化。Dart中List属于可变对象,你直接将event.curr_reports赋值给updated_reports,后续修改列表元素时,列表本身的引用并未改变,导致Equatable认为新旧ReportsLoadSuccess状态相等,因此Bloc不会通知UI重建。

另外需确保Report和Message类也正确继承并实现Equatable,否则即使列表引用改变,Equatable也无法准确检测到内部元素的变化。

修复步骤

  1. 创建列表的全新副本
    在_OnReportMessageSubmitted方法中,不要直接复用原列表引用,而是创建新的列表副本,断开与原状态列表的关联:

    // 替换原有赋值方式,生成新列表
    List<Report> updated_reports = [...event.curr_reports];
    // 也可使用List.from方式
    // List<Report> updated_reports = List.from(event.curr_reports);
    
  2. 确保Report类实现Equatable
    Report类需要继承Equatable,并将reportId、messages等核心属性加入props,保证元素内容变化时能被Equatable检测到:

    class Report extends Equatable {
      final String reportId;
      final List<Message> messages;
      // 其他属性...
    
      const Report({required this.reportId, required this.messages});
    
      Report copyWith({
        String? reportId,
        List<Message>? messages,
      }) {
        return Report(
          reportId: reportId ?? this.reportId,
          messages: messages ?? this.messages,
        );
      }
    
      @override
      List<Object> get props => [reportId, messages];
    }
    
  3. 确保Message类实现Equatable
    Message类同样需要正确实现Equatable,保证消息内容的变化能被上层列表的Equatable比较感知:

    class Message extends Equatable {
      final String id;
      final String content;
      // 其他属性...
    
      const Message({required this.id, required this.content});
    
      factory Message.fromJson(Map<String, dynamic> json) {
        return Message(
          id: json['id'],
          content: json['content'],
        );
      }
    
      @override
      List<Object> get props => [id, content];
    }
    

修改后的_bloc方法代码

void _OnReportMessageSubmitted(
  ReportMessageSubmitted event,
  Emitter<ReportsState> emit,
) async {
  final DataState dataState =
      await _reportsRepository.addMessage(event.messageData);

  if (dataState is DataSuccess) {
    // 创建列表副本,断开原引用
    List<Report> updated_reports = [...event.curr_reports];
    int index = updated_reports.indexWhere(
      (_element) => _element.reportId == dataState.data['reportConvId'],
    );
    updated_reports[index] = updated_reports[index].copyWith(
      messages: [
        ...updated_reports[index].messages,
        Message.fromJson(dataState.data),
      ],
    );
    emit(ReportsLoadSuccess(updated_reports));
  } else {
      //...
  }
}

内容的提问来源于stack exchange,提问作者Abdeljalil Bouchfar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:05:17