Bloc: Combining multiple futures in BlocState

Created on 5 Mar 2020  路  3Comments  路  Source: felangel/bloc

Is your feature request related to a problem? Please describe.
I want to asynchronously combine multiple futures from different endpoints in a single BlocState.

For example, I would like to combine the results of getString and getInt from this Repository class.

// * repository.dart
abstract class Repository {
  Future<String> getString();
  Future<int> getInt();
}

The resulting state exposed by MyBloc should look something like this:

// * my_bloc_state.dart
...
class MyStateSuccess extends MyState {
  MyStateSuccess(this.stringResult, this.intResult);

  final String stringResult;
  final int intResult;
}
...

Describe the solution you'd like
Ideally, I want to simply fire both futures and independently yield the results to MyStateSuccess whenever the futures complete.

Describe alternatives you've considered
Currently, I simply await both futures in MyBloc and yield once both futures complete.

// * my_bloc.dart

class MyBloc extends Bloc<MyEvent, MyState> {
  final Repository repository;

  Stream<MyState> combineGetFutures() async* {
    final string = await repository.getString();
    final int = await repository.getInt();

    yield MyStateSuccess(string, int);
  }

  ...
}

My questions

  1. Is it possible to somehow await the multiple futures simultaneously, and yield the results to the same MyState? I tried working with Future.wait(futures) as seen in a StackOverflow question, but the futures need to have an identical return type.
  2. Does the dependency of MyStateSuccess on both futures, indicate that MyBloc has too much responsibility?

EDIT: for context, I want to combine the results of different JSON API endpoints to a page that depends on data from the different endpoints.

question

Most helpful comment

Your answers were exactly what I was looking for, thank you.

All 3 comments

You can do it using List<Object> results = await Future.wait(futures). You can then do something like: final string stringResult = results.first;

Hi @sterrenburg 馃憢
Thanks for opening an issue!

You can definitely do that in multiple ways.
If you want to get the data in series:

class MyBloc extends Bloc<MyEvent, MyState> {
  final Repository repository;

  Stream<MyState> combineGetFutures() async* {
    final resultA = await repository.getString();
    final resultB = await repository.getInt();

    yield MyStateSuccess(resultA, resultB);
  }

  ...
}

And if you want to get the data in parallel:

class MyBloc extends Bloc<MyEvent, MyState> {
  final Repository repository;

  Stream<MyState> combineGetFutures() async* {
    final results = await Future.wait([
      repository.getString(),
      repository.getInt()
    ]);
    final resultA = results.first;
    final resultB = results.last;

    yield MyStateSuccess(resultA, resultB);
  }

  ...
}

Hope that helps! 馃憤

Your answers were exactly what I was looking for, thank you.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tigranhov picture tigranhov  路  3Comments

krusek picture krusek  路  3Comments

shawnchan2014 picture shawnchan2014  路  3Comments

wheel1992 picture wheel1992  路  3Comments

MahdiPishguy picture MahdiPishguy  路  3Comments