I'm building a tic-tak-toe app and I decided to learn BLoC for Flutter along. I hava a problem with the BlocBuilder
widget.
As I think about it. Every time Cubit/Bloc that the bloc builder widget listens to emits new state the bloc builder goes through this routine:
Call
buildWhen
callback passing previous state as theprevious
parameter and the newly emitted state as thecurrent
parameter.If the
buildWhen
callback returned true then rebuild.During rebuilding call the
builder
callback passing given context ascontext
parameter and the newly emitted state asstate
parameter. This callback returns the widget that we return.
So the conclusion is that the current
parameter of the buildWhen
call is always equal to the state
parameter of the builder
call. But in practice it's different:
BlocBuilder<GameCubit, GameState>(
buildWhen: (previous, current) => current is SetSlotSignGameState && (current as SetSlotSignGameState).slotPosition == widget.pos,
builder: (context, state) {
var sign = (state as SetSlotSignGameState).sign;
// Widget creation goes here...
},
);
In the builder
callback, it throws:
The following _CastError was thrown building BlocBuilder<GameCubit, GameState>(dirty, state: _BlocBuilderBaseState<GameCubit, GameState>#dc100): type 'GameState' is not a subtype of type 'SetSlotSignGameState' in type cast The relevant error-causing widget was: BlocBuilder<GameCubit, GameState>
The method where I emit the states that is in the GameCubit
class:
// [pos] is the position of the slot clicked
void setSlotSign(Vec2<int> pos) {
// Some code
emit(SetSlotSignGameState(/* Parameter representing the sign that is being placed in the slot*/, pos));
// Some code
emit(TurnChangeGameState());
}
Briefly about types of states. SetSlotSignGameState
is emitted when a user taps on a slot in the tic-tac-toe grid and the slot is empty. So this state means that we need to change sign in some slot. TurnChangeGameState
is emitted when we need to give the turn to the next player.
Temporary solution. For now I fixed it by saving the state from buildWhen
callback in a private field of the widget's state and then using it from the builder. BlocListener
also has this problem but there I can just move the check from listenWhen
callback into listen
callback. The disadvantage of this solution is that it's very inelegant and inconvenient.
buildWhen: (previous, current) => current is SetSlotSignGameState && (current as SetSlotSignGameState).slotPosition == widget.pos) <-- THIS BRACKET HAS NO PAIR,
. That was by mystake ? – jorjdaniel