Reputation: 2678
My 2nd strange event today. When I follow the debugger inside bloc.dart (the library, not my file) and I see that transition.nextState == state && _emitted
is false
, it does not update my widget (nextState has list size 2, state has 10 - _emitted is true). To my understanding the builder should be ok, is there any other spot to look at why it does not update?
Just to explain the logic before I show the code
I fetch my data upon app launch with
BlocProvider(create: (context) =>
LogicGraphsPStmntBloc(logicGraphsRepository:
logicGraphsRepository)..add(LogicGraphsNextProblemRequested()),
this returns a list of 10 strings, which I store in my _bloc.dart file (not sure if this is state of the art)
These 10 strings are sent via the state LogicGraphsPStmntLoadSuccess(statements)
and are properly rendered as buttons
If I click a button, only the 1st and the selected string shall be shown. The event is properly triggered with onPressed: () {BlocProvider.of<LogicGraphsPStmntBloc>(context).add(LogicGraphsPStmntCollapsed(statement: index-1));},
This properly triggers the state yield LogicGraphsPStmntLoadSuccess(statementsShown);
with now only 2 elements in the list (as compared to 10 in step 3) but it does not cause a rerendering
If I step into the state with the debugger, I can see that both states have a different number of elements.
my states
abstract class LogicGraphsPStmntState extends Equatable {
const LogicGraphsPStmntState();
@override
List<Object> get props => [];
}
class LogicGraphsPStmntLoadSuccess extends LogicGraphsPStmntState {
const LogicGraphsPStmntLoadSuccess([this.statements = const []]);
final List<String> statements;
@override
List<Object> get props => [];
@override
String toString() => 'LogicGraphsPStmntLoadSuccess { statements: $statements }';
}
my bloc (not exactly, because the code inside my sub functions to release a state are not reached as described in my other issue. So currently I have those sub functions lines as spaghetti in the mapEventToState=
class LogicGraphsPStmntBloc extends Bloc<LogicGraphsPStmntEvent, LogicGraphsPStmntState> {
LogicGraphsPStmntBloc({@required this.logicGraphsRepository}) : super(LogicGraphsPStmntInProgress());
final LogicGraphsRepository logicGraphsRepository;
List<String> statements;
int currentProblem = -1;
@override
Stream<LogicGraphsPStmntState> mapEventToState(LogicGraphsPStmntEvent event) async* {
if (event is LogicGraphsNextProblemRequested) {
_mapLGPStmntNewProblemRequested();
_mapLGPStmntLoadRequested(currentProblem);
}
else if (event is LogicGraphsPStmntLoadRequested) {
_mapLGPStmntLoadRequested(currentProblem);
}
else if (event is LogicGraphsPStmntCollapsed) {
_mapLGPStmntCollapseRequested(event);
}
Stream<LogicGraphsPStmntState> _mapLGPStmntNewProblemRequested() async* {
try {
currentProblem =
await getNextProblem(currentProblem == null ? -1 : currentProblem);
statements =
await logicGraphsRepository.getProblemStmntList(currentProblem);
_mapLGPStmntLoadRequested(currentProblem);
} catch (_) {
yield LogicGraphsPStmntLoadFailure();
}
}
Stream<LogicGraphsPStmntState> _mapLGPStmntLoadRequested(int problem) async* {
try {
yield LogicGraphsPStmntLoadSuccess(statements);
} catch (_) {
yield LogicGraphsPStmntLoadFailure();
}
}
Stream<LogicGraphsPStmntState> _mapLGPStmntCollapseRequested(
LogicGraphsPStmntCollapsed event) async* {
List<String> statementsShown = [];
statementFocussed = event.statement;
statementsShown.add(statements[0]);
statementsShown.add(statements[statementFocussed]);
yield LogicGraphsPStmntLoadSuccess(statementsShown);
}
}
my widgets
class LogicGraphPage extends StatelessWidget {
final LogicGraphsRepository logicGraphsRepository = LogicGraphsRepository(
logicGraphsApiClient: LogicGraphsApiClient());
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: BlocProvider(
create: (context) =>
LogicGraphsPStmntBloc(logicGraphsRepository: logicGraphsRepository)
..add(LogicGraphsNextProblemRequested()),
child:BlocBuilder<LogicGraphsPStmntBloc, LogicGraphsPStmntState>(
builder: (context, state) {
if (state is LogicGraphsPStmntLoadSuccess) {
final List<String> statements = state.statements;
return ListView.builder(
itemCount: statements.length,
itemBuilder: (BuildContext context, int index) {
return CupertinoButton(
padding: EdgeInsets.all(0),
child: Text(statements[index])
onPressed: () {BlocProvider.of<LogicGraphsPStmntBloc>(context).add(LogicGraphsPStmntCollapsed(statement: index-1));},
);
});
}
else return Container();
}
)
),
);
}
}
The function inside the bloc.dart library where I would assume that the new state is emitted. You see the line if (transition.nextState == state && _emitted) return;
. Next state has 2 elements, state has 10, _emitted is true, so I would assume the code to continue. Instead the return is triggered and lines withemit(transition.nextState);
are skipped.
Any help is highly appreciated, since this is my first experience with BLoC/equatable and flutter in general is also still quite new to me. But I am progressing!
void _bindEventsToStates() {
_transitionSubscription = transformTransitions(
transformEvents(
_eventController.stream,
(event) => mapEventToState(event).map(
(nextState) => Transition(
currentState: state,
event: event,
nextState: nextState,
),
),
),
).listen(
(transition) {
if (transition.nextState == state && _emitted) return; // <<<<<<<<<<<
try {
onTransition(transition);
emit(transition.nextState);
} on dynamic catch (error, stackTrace) {
onError(error, stackTrace);
}
_emitted = true;
},
onError: onError,
);
}
Upvotes: 1
Views: 2058
Reputation: 86
I guess the bloc can't tell the difference between LogicGraphsPStmntLoadSuccess(statements)
and LogicGraphsPStmntLoadSuccess(statementsShown)
as they are the same state and I think it cannot spot the differences between the different parameters.
So what I suggest to do is this:
before yielding LogicGraphsPStmntLoadSuccess(statementsShown)
try to yield a "switching" state like I don't know LogicGraphsPStmntChangeStatement
before that.
So:
yield LogicGraphsPStmntChangeStatement;
yield LogicGraphsPStmntLoadSuccess(statementsShown);
That should do the trick.
Upvotes: 2