Flutter中emit新状态时BlocBuilder不重建Widget问题排查
井字棋Cubit状态更新后BlocConsumer不重建的问题解决
问题概述
开发井字棋学习Bloc/Cubit状态管理时,玩家点击格子后棋盘无法渲染更新,调用cubit.makePlay触发emit新状态,但BlocConsumer的builder方法不执行,界面无变化。
核心问题与修复方案
1. GameState未正确实现Equatable的props对比
GameState继承自Equatable,但props返回空列表,导致Equatable无法判断状态是否发生变化,Bloc会认为新状态与旧状态相同,因此不触发UI重建。
修复代码:
修改GameState中的props,包含所有需要参与状态对比的字段:
@override List<Object?> get props => [ status, playerTurn, drawGameScore, oPlayerScore, xPlayerScore, board, gameWinner, ];
2. _hasWinner与_hasDraw方法使用旧状态判断
当前_hasWinner和_hasDraw直接使用state.board判断,但此时已经生成了新的棋盘actualBoard,判断逻辑会基于旧棋盘执行,导致胜负判断错误。
修复代码:
将两个方法改为接收新棋盘参数:
bool _hasWinner(List<String> board) { if (board[0] != '' && board[0] == board[1] && board[0] == board[2] || board[3] != '' && board[3] == board[4] && board[3] == board[5] || board[6] != '' && board[6] == board[7] && board[6] == board[8] || board[0] != '' && board[0] == board[4] && board[0] == board[8] || board[2] != '' && board[2] == board[6] && board[2] == board[4] || board[0] != '' && board[0] == board[3] && board[0] == board[6] || board[1] != '' && board[1] == board[4] && board[1] == board[7] || board[2] != '' && board[2] == board[5] && board[2] == board[8]) { return true; } return false; } bool _hasDraw(List<String> board) => !board.contains('');
在makePlay中调用时传入新棋盘:
if (_hasWinner(actualBoard)) { // ... 状态发射逻辑 } else if (_hasDraw(actualBoard)) { // ... 状态发射逻辑 }
3. 获胜/平局状态被立即重置覆盖
当前makePlay中emit获胜/平局状态后,立即调用resetBoard发射重置状态,导致UI还未响应胜负状态就被重置。需将重置逻辑移到弹窗关闭时执行。
修复代码:
移除makePlay中获胜/平局分支的resetBoard()调用,修改_showWinDialog的按钮逻辑:
void _showWinDialog({ required BuildContext context, required GameCubit cubit, required String winner, }) { cubit.increaseWinScore(winner: winner); showDialog( barrierDismissible: false, context: context, builder: (BuildContext context) { return AlertDialog( title: Text(' $winner venceu!'), actions: [ TextButton( child: const Text("Jogar novamente"), onPressed: () { cubit.resetBoard(); Navigator.of(context).pop(); }, ) ], ); }, ); }
同时确保emit胜负状态时更新棋盘:
emit( state.copyWith( status: GameStatus.hasWinner, gameWinner: playerTurn, playerTurn: revertPlayerTurn(actualPlayer: playerTurn), board: actualBoard, // 新增棋盘更新 ), );
4. increaseWinScore方法的得分更新错误
当前increaseWinScore的else分支错误更新了xPlayerScore,需修正为oPlayerScore:
void increaseWinScore({required String winner}) { if (winner == 'X') { emit(state.copyWith(xPlayerScore: state.xPlayerScore + 1)); } else { emit(state.copyWith(oPlayerScore: state.oPlayerScore + 1)); } }
并在胜负弹窗中调用该方法更新得分。
内容的提问来源于stack exchange,提问作者Marcelo Arthur
相关产品推荐
相关产品推荐

