Bloc: How to pass a bloc to another bloc on MultiBlocProvider to listen the state changes [Best Practice]

Created on 30 Sep 2020  路  6Comments  路  Source: felangel/bloc

Let's assume I create MultiBlocProvider on main.dart that wraps all widget trees. I need to pass bloc A to the bloc B to listen to bloc A's state changes inside bloc B. First I tried this:

MultiBlocProvider(
  providers: [
    BlocProvider<BlocA>(
      create: (BuildContext context) => BlocA(),
    ),
    BlocProvider<BlocB>(
      create: (BuildContext context) => BlocB(context.bloc<BlocA>()),
    ),
    BlocProvider<BlocC>(
      create: (BuildContext context) => BlocC(),
    ),
  ],
  child: ChildA(),
)

and

MultiBlocProvider(
  providers: [
    BlocProvider<BlocA>(
      create: (BuildContext context) => BlocA(),
    ),
    BlocProvider<BlocB>(
      create: (BuildContext context) => BlocB(BlocA()),
    ),
    BlocProvider<BlocC>(
      create: (BuildContext context) => BlocC(),
    ),
  ],
  child: ChildA(),
)

Of course, It's not working. Is there any way to access newly created bloc A instance to be passed directly to bloc B?

I ended up always using these two approaches in my projects:

  1. Nested BlocProvider
MultiBlocProvider(
  providers: [
    BlocProvider<BlocA>(
      create: (BuildContext context) => BlocA(),
    ),
    BlocProvider<BlocC>(
      create: (BuildContext context) => BlocC(),
    ),
  ],
  child: BlocProvider<BlocB>(
    create: (BuildContext context) => BlocB(context.bloc<BlocA>()),
    child: ChildA(),
  ),
)
  1. Inject bloc A to bloc B down in the widget tree.
    So instead of listening for bloc A's state changes, I inject bloc A to dispatch bloc A's event inside bloc B

Is my approach considered anti-pattern? I'd like to know the best practice for this specific use case. Thank you.

question

All 6 comments

Hi @tijanirf 馃憢

Your first attempt is what works actually and it's the easiest approach you can take:

void main() {
  runApp(
    MultiBlocProvider(
      providers: [
        BlocProvider(create: (_) => ABloc()),
        BlocProvider(
          create: (context) => BBloc(context.bloc<ABloc>()),
        ),
      ],
      child: const MyApp(),
    ),
  );
}

Keep in mind that for your listening on first bloc's state to work inside second bloc, the second bloc has to be instantiated, so make sure you're either consuming it's state in the UI or you're setting lazy: false when providing it.

Hope that helps but if you're still struggling then feel free to share a minimal reproduction repository and I'll have a look 馃憤

Thanks @narcodico for the response

But as long as I remember, my first approach is not working. Maybe I'll try it again after work on a new repository and share the result.

Meanwhile, do you see any breaking behavior possibility on my second approach (Inject bloc A to bloc B down in the widget tree)? Because I think it's pretty easy to inject the bloc as I don't need to provide multiple blocs on the root of the widget tree. It seems it is better to put BlocProvider as close as possible to the BlocBuilder/the consumer.

If you're not planning to listen to bloc A's state inside bloc B then there's no point in injecting it. You could keep things separated by using a BlocListener with bloc B and add events to your bloc A in response to state changes from bloc B. You should always aim to avoid injecting blocs into each other when possible.

So I created simple reproduction of my first approach, it turns out it works. I definitely will check the implementation in my real project, my bad :disappointed:

Btw, I also created an example of my second approach (Inject bloc A to bloc B down in the widget tree). Could you please see if it is considered good practice? as it achieves the same purpose. Thank you in advance @narcodico :bow:

As long as you only need the SigninBloc in the sign in screen it makes sense to only provide it on top of that screen.
As for injecting it's not breaking any rules, so it's up to you if you do it like so, or if you're using a BlocListener to add events to auth bloc based on the incoming states from sign in. I suggest avoiding injecting blocs as much as possible, it's better to keep things decoupled.

I see, i got your point about keeping things decouple. Thanks a lot @narcodico 馃憦

Was this page helpful?
0 / 5 - 0 ratings

Related issues

abinvp picture abinvp  路  3Comments

MahdiPishguy picture MahdiPishguy  路  3Comments

shawnchan2014 picture shawnchan2014  路  3Comments

rsnider19 picture rsnider19  路  3Comments

hivesey picture hivesey  路  3Comments