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拦截。
修复方案
按以下步骤修改代码即可解决问题:
修正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,直接继承基类实现即可。修正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子类按相同规则补充即可。
清理builder中的副作用代码
删除BlocBuilder中_list = state.list;这行赋值代码,不要在builder函数内执行任何与UI返回无关的逻辑,避免不可预期的重建导致数据错乱。
额外排查点
如果完成上述修改后仍存在渲染问题,做两项检查:
- 确认
GameList组件的构造函数没有被错误加const修饰,导致组件无法接收新参数更新 - 确认
GameList内部没有缓存首次传入的list引用,每次收到新的list参数时全量替换数据源,不要保留旧列表引用 - 代码中多处使用
!做强制非空断言,建议增加空判断逻辑,避免极端场景下触发运行时异常
内容的提问来源于stack exchange,提问作者mollusk
相关产品推荐
相关产品推荐

