You need to enable JavaScript to run this app. Flutter BLoC架构下GameBloc触发事件后返回相同DrinkCard列表的问题
优惠活动
大模型
产品
解决方案
定价
更多

Flutter BLoC架构下GameBloc触发事件后返回相同DrinkCard列表的问题

核心问题与修复步骤

1. 未实现GameReloaded事件处理

你的GameBloc仅处理了GamePrepare事件,派发的GameReloaded没有任何对应逻辑,直接被Bloc丢弃,不会重新生成卡牌。
在mapEventToState中补充处理逻辑:

if (event is GameReloaded) {
  yield GameLoaded(
    cards: _getCards(event.deck, playerCubit.state),
  );
}

2. 错误使用未定义变量,且未复用传入的玩家参数

_getCards方法接收了players参数,却调用了未在GameBloc中定义的playerCubit.state,既会报错,也无法获取最新玩家数据。

  • 给GameBloc注入PlayerCubit依赖:
class GameBloc extends Bloc<GameEvent, GameState> {
  GameBloc({
    required this.repository,
    required this.playerCubit,
  }) : super(GameInitial());
  final GameRepository repository;
  final PlayerCubit playerCubit;
  • 修正_getCards的参数使用,优先用传入的玩家数据:
List<DrinkCard> _getCards(DeckType deckId, List<Player> players) {
  final allCards = DeckRepository.getDeckById(deckId).cards;
  // 不要写playerCubit.state,用传入的players
  final processedCards = DeckRepository.prepareCards(allCards, players);
  return processedCards;
}

3. 弹窗中创建了独立的GameBloc实例

showModalBottomSheet内的BlocProvider创建了一个全新的GameBloc,和外层显示卡牌的GameBloc完全独立。你在弹窗中派发的所有事件都只会发给新实例,外层的Bloc根本收不到通知,自然不会更新卡牌。
删除弹窗内的多余BlocProvider,直接使用外层已经提供的Bloc实例:

await showModalBottomSheet(
  context: context,
  builder: (ctx) {
    // 移除原来的BlocProvider包裹逻辑
    return ModalSheetBody(
      height: height,
      controller: _controller,
      index: _controller.index,
      callback: () { /* ... */ },
    );
  },
)

4. 直接修改可变列表,未触发PlayerCubit状态更新

你直接对PlayerCubit.state(List)调用add方法,List是引用类型,修改原实例不会触发Cubit的状态通知。哪怕后续派发GameReloaded事件,获取的玩家列表也可能是旧数据。

  • 给PlayerCubit添加专用的修改方法,内部创建新列表再emit:
// PlayerCubit内部实现
void addPlayer(Player player) {
  emit(List<Player>.from(state)..add(player));
}

void removePlayer(String playerName) {
  emit(List<Player>.from(state)..removeWhere((p) => p.name == playerName));
}
  • 替换原来的直接修改逻辑:
// 错误代码:context.read<GameBloc>().playerCubit.state.add(Player(name: name[0]));
context.read<PlayerCubit>().addPlayer(Player(name: name[0]));

5. 复用静态卡牌列表引用导致状态判断失效

如果DeckRepository.getDeckById返回的是同一个静态列表实例,且prepareCards直接在原列表上操作,Bloc的状态相等判断(尤其是Equatable对列表的判断)可能会因为引用复用跳过状态更新。
在_getCards中先复制原卡牌列表,避免修改静态源:

List<DrinkCard> _getCards(DeckType deckId, List<Player> players) {
  // 先复制原列表,生成新的实例
  final allCards = List<DrinkCard>.from(DeckRepository.getDeckById(deckId).cards);
  final processedCards = DeckRepository.prepareCards(allCards, players);
  return processedCards;
}

6. Build阶段派发事件覆盖正常状态

CardStack的BlocBuilder在收到非GameLoaded状态时,会派发使用临时玩家a/b的GamePrepare事件,可能覆盖你后续触发的正常更新事件。
删除CardStack里的自动派发逻辑,改为在应用初始化/Bloc首次创建时触发一次GamePrepare即可,不要在build方法内派发Bloc事件。

内容的提问来源于stack exchange,提问作者Bruno J.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.27 08:27:00