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

Flutter Bloc状态变更后GameList组件未触发重建问题

问题根因

核心问题为Equatable相等性判断配置错误,属于Bloc开发中UI不跟随状态更新的典型诱因:

  • Bloc触发BlocBuilder重建的判断标准是「新发射的状态与上一状态不相等」,相等性逻辑完全由Equatable实现:两个状态若runtimeType一致,且props列表中所有属性值相等,就会被判定为同一状态,Bloc会直接丢弃本次状态发射,不通知UI更新。
  • 现有代码中GameState基类重写的props直接返回空数组[],FilterGamesState、ListLoadedState、FailState等所有子类均未重写props,未将自身持有的列表、错误信息等属性加入对比范围。这就导致两次发射的FilterGamesState即使列表内容完全不同,也会被判定为相等状态,Bloc拦截更新后UI自然不会重建。
  • 额外隐患:BlocBuilder的builder函数应为纯函数,仅根据输入state返回对应widget,你在builder内执行_list = state.list的赋值操作属于副作用,Flutter触发widget重建的时机不可控,这类写法很容易导致变量值错乱。同时Event类的props也返回空数组,会导致重复触发同类型事件时被Bloc拦截。
修复方案

按以下步骤修改代码即可解决问题:

  1. 修正State类的Equatable配置
    首先修改GameState基类,将基类定义的公共属性加入props:

    abstract class GameState extends Equatable {
      final Game? item;
      final List<Game>? list;
      const GameState({this.item, this.list});
    
      @override
      List<Object?> get props => [item, list];
    }
    

    给每个持有额外属性的State子类重写props,合并基类属性与自身属性:

    // FailState
    class FailState extends GameState {
      const FailState({required this.message});
      final String message;
    
      @override
      List<Object?> get props => [...super.props, message];
    }
    
    // ListLoadedState
    class ListLoadedState extends GameState {
      const ListLoadedState({required List<Game> listGame}) : super(list: listGame);
    
      @override
      List<Object?> get props => [...super.props];
    }
    
    // ItemLoadedState
    class ItemLoadedState extends GameState {
      const ItemLoadedState({required Game game}) : super(item: game);
      final Game game;
    
      @override
      List<Object?> get props => [...super.props, game];
    }
    
    // FilterGamesState
    class FilterGamesState extends GameState {
      const FilterGamesState({required List<Game> listGame}) : super(list: listGame);
    
      @override
      List<Object?> get props => [...super.props];
    }
    

    LoadingState、GameInitial没有自定义额外属性,不需要重写props,直接继承基类实现即可。

  2. 修正Event类的Equatable配置
    修改GameEvent基类,将公共属性加入props:

    abstract class GameEvent extends Equatable {
      final Game? item;
      const GameEvent({this.item});
    
      @override
      List<Object?> get props => [item];
    }
    

    给持有额外属性的Event子类重写props,比如FilterGamesEvent:

    class FilterGamesEvent extends GameEvent {
      const FilterGamesEvent({required this.list});
      final List<Game>? list;
    
      @override
      List<Object?> get props => [...super.props, list];
    }
    

    其他持有自定义属性的Event子类按相同规则补充即可。

  3. 清理builder中的副作用代码
    删除BlocBuilder中_list = state.list;这行赋值代码,不要在builder函数内执行任何与UI返回无关的逻辑,避免不可预期的重建导致数据错乱。

额外排查点

如果完成上述修改后仍存在渲染问题,做两项检查:

  • 确认GameList组件的构造函数没有被错误加const修饰,导致组件无法接收新参数更新
  • 确认GameList内部没有缓存首次传入的list引用,每次收到新的list参数时全量替换数据源,不要保留旧列表引用
  • 代码中多处使用!做强制非空断言,建议增加空判断逻辑,避免极端场景下触发运行时异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 12:33:13