For many reasons it would be awesome if we could wait for the bloc to finish with the event before continuing.
Here's an example
Future<void> testBloc(
) async {
final data = await request('fetch-user');
final user = UserV1.fromJson(data);
// Bloc is access via static reference, it has to be this way.
userBloc.add(UpdateUserAction(user));
// Fails because it needs userBloc.state.user.uid
fetchAllLogs();
}
I can't seem to find a solution or feature for it. If anyone knows it would be great.
Hi @ollydixon 馃憢
Why not invoke fetchAllLogs in the UpdateUserAction handler ? e.g.:
if (event is UpdateUserAction) {
// process event
fetchAllLogs();
}
@RollyPeres fetchAllLogs also has a logsBloc with add. :-/ I'm sort of stuck here; thanks for the reply.
fetchAllLogs has to finish and await and add before continuing.
Hi @ollydixon 馃憢
Thanks for opening an issue!
If you really need to do this you can do
userBloc.add(UpdateUserAction(user));
final nextState = await userBloc.first;
fetchAllLogs();
But this is usually not the best solution and is likely an indication that the flow of data can be reworked/simplified.
@felangel thank you so much! I've been stuck on this all day.
@felangel it would seem that the state is still invalid even after the await.
For example.
await userBloc.first;
userBloc.state.logs << 0
But if I wait for a second then run it again, userBloc.state.logs is 151.
Hmm stumped.
await userBloc.first would wait for the next state. If you're yielding multiple states for a single event you need to do firstWhere
@felangel I'm guessing firstWhere will just return the next state that was just added? (Matching the bool)
@ollydixon yup 馃憤
Closing this for now but feel free to comment with additional questions and I'm happy to continue the conversation 馃憤
@felangel thanks :-)
Would you ever consider adding await bloc.add to guarantee a consistent API for say 'next' event processes. Just an idea; maybe I sound dumb.
Great job on this lib btw. We deleted all our Redux from over 30 Flutter projects at my company.
@ollydixon I would like to avoid that because add is part of the Sink api which does not return a Future and also it would be confusing because a single add can result in multiple state changes so you would never know when the event was actually "done" being processed.
@felangel makes sense. I guess it's never reliable to assume values from distant state anyhow. Sticking to the firstWhere seemed to work perfect for our auth fetching scenarios. :-)
You can accomplish this more easily using Cubit (in v6.0.0 of bloc)
class MyCubit extends Cubit<MyState> {
MyCubit() : super(MyState.initial());
Future<void> doSomething() async {
emit(MyState.loading());
final result = await _repository.getResult();
emit(MyState.success(result));
}
}
Then you can await doSomething directly:
final cubit = MyCubit();
await cubit.doSomething();
print(cubit.state); // MyState.success
Hope that helps and thanks so much for the positive feedback -- I really appreciate it 馃檹
Thanks, I'll look into this; little abstract for my brain haha; most of our state/actions are in order, the stream stuff always confuses my coders.
For example it's as simple as:
Future<UserV1> updateUser(Map<String, dynamic> data) async {
try {
final json = await request('update-user', data: data);
final user = UserV1.fromJson(json);
userBloc.add(UpdateUser(user));
return updatedUser;
} catch (e) {
print('Error updating user');
print(e);
throw e;
}
}
The the UI handles the rest. Errors are handled directly and not in state management. We like as little code as possible! :-)
Most helpful comment
await
userBloc.firstwould wait for the next state. If you're yielding multiple states for a single event you need to dofirstWhere