Bloc: Allow multiple blocs in BlocListener and BlocBuilder

Created on 15 Jul 2019  路  3Comments  路  Source: felangel/bloc

Is your feature request related to a problem?

Similar to https://github.com/felangel/bloc/issues/396

My case is for BlocListener but can apply for BlocBuilder

I have an AuthBloc, and ThemeBloc (Ancestor of Material App for update theme)

When the AuthState is Loading I show loading screen.
When AuthState is Authenticated I dispatch a event to ThemeBloc to load the theme in a repository(cloud);
Also When AuthState is Authenticated I navigate to Home.


BlocListener(
  blocs: authBloc,
  listener (context, authState){
    if(authState ==  authState.authenticated){
          _nagivateToHome(contex);
    }
  }
)

I like to navigate to home only when the AppState is fetched with the correct theme and the AuthBloc is Authenticated.

If I no do that, when the app navigate to home, the home have the defaultTheme and when the theme is loaded the theme is updated, in this time, you can see the theme changing at runtime, I

I want the user navigate to home and see the home with the correct theme.

I pop a Loading Screen when AuthState is Loading, and can show a other LoadingScreen when the theme is fetching, but you can see the change when use pop and push for the differents loading screens.

Describe the solution you'd like

Widgets like BlocListener2 BlocListener3 BlocListenerN

BlocListener2(
  blocs: authBloc, themeBloc,
  listener (context, authState, themeState){
    if(authState ==  authState.authenticated && themeState is ThemeLoaded){
          _nagivateToHome(contex);
    }else if (state ==  authState.not_authenticated){
         _navigateToLogin(context);
    }
  }
)

Describe alternatives you've considered

  1. I want to know if I can create a Bloc that have dependencies in this 2 blocs, in this way, I can listen this new bloc, with the BlocListener and BlocBuilder. But I don't know what is the name of this bloc. Create other bloc, seen better solution, and you can share with other platform.
  1. The AuthBloc can have dependency of ThemeBloc and yield the Authenticated state when the the user is authenticated and the theme is loaded, it seems that the AuthBloc is doing things different from their responsibilities.
question

Most helpful comment

Hi @basketball-ico 馃憢
Thanks for opening an issue!

  1. You can create a new bloc which has dependencies on the two blocs and uses combineLatest to combine the state streams into a single stream which it dispatches events in response to. You can then use the single bloc in your BlocListener or BlocBuilder instead of having to keep creating BlocListener1...BlocListenerN.

  2. You can instead have a HomeBloc which subscribes to the AuthBloc and ThemeBloc and dispatches an event when AuthBloc is Authenticated and ThemeBloc is loaded.

I'd prefer not to introduce these widgets because you can always nest BlocBuilders and BlocListeners and they are also easy to implement so you can implement them for your own use-cases. I'm not sure they are core components which should belong in the flutter_bloc library. Thoughts?

All 3 comments

Hi @basketball-ico 馃憢
Thanks for opening an issue!

  1. You can create a new bloc which has dependencies on the two blocs and uses combineLatest to combine the state streams into a single stream which it dispatches events in response to. You can then use the single bloc in your BlocListener or BlocBuilder instead of having to keep creating BlocListener1...BlocListenerN.

  2. You can instead have a HomeBloc which subscribes to the AuthBloc and ThemeBloc and dispatches an event when AuthBloc is Authenticated and ThemeBloc is loaded.

I'd prefer not to introduce these widgets because you can always nest BlocBuilders and BlocListeners and they are also easy to implement so you can implement them for your own use-cases. I'm not sure they are core components which should belong in the flutter_bloc library. Thoughts?

@felangel thanks 馃.

Yes, I like the idea of have this logic in pure Dart, in this way I can reuse with AngularDart.

So my HomeBloc is at the root of my app.

enum HomeEvent { appStarted, loaded }
enum HomeState { notLoaded, loaded }

class HomeBloc extends Bloc<HomeEvent, HomeState> {
  final AuthBloc authBloc;
  final ThemeBloc themeBloc;

  StreamSubscription<bool> _blocsSubscription;

  HomeBloc(this.authBloc, this.themeBloc);

  HomeState get initialState => HomeState.notLoaded;

  @override
  void dispose() {
    _blocsSubscription?.cancel();
    super.dispose();
  }

  @override
  Stream<HomeState> mapEventToState(HomeEvent event) async* {
    if (event == HomeEvent.appStarted) {
      _blocsSubscription = Observable.combineLatest2(
        authBloc.state,
        themeBloc.state,
        (authState, themeState) {
          return authState is AuthAuthenticated && themeState is ThemeLoaded;
        },
      ).listen((isHomeLoaded) => dispatch(HomeEvent.loaded));
    } else if (event == HomeEvent.loaded) {
      yield HomeState.loaded;
    }
  }
}
BlocListener(
  bloc: homeBloc,
  listener: (BuildContext context, HomeState state) {
    if(state == HomeState.loaded){
      _nagivateToHome(contex);
    }
  },
  child: MyChid();
)

Do you have any suggestion? 馃

`

overall looks good but I would make sure to only dispatch HomeEvent.loaded if isHomeLoaded is true and I would also make sure to cancel the previous subscription before creating a new one

_blocsSubscription?.cancel();
_blocsSubscription = Observable.combineLatest2(...);

Closing for now but feel free to comment with additional questions and I'm happy to continue the conversation 馃憤

Was this page helpful?
0 / 5 - 0 ratings

Related issues

abinvp picture abinvp  路  3Comments

ricktotec picture ricktotec  路  3Comments

1AlexFix1 picture 1AlexFix1  路  3Comments

nerder picture nerder  路  3Comments

komapeb picture komapeb  路  3Comments