flutterdartblocstate-management

Is it allowed to add event to another bloc from inside of a bloc?


I am using bloc library available in Dart to implement "bloc" pattern. I will eventually move onto flutter_bloc library so I can use it inside a real app.

I'm having a bit of difficulty understanding how to create some general blocs that can be called from within more specialized blocs. By specialized I mean some bloc that perhaps manages a specific view. General blocs would then take care of calling APIs or maybe even doing multiple things sequentially.

So my idea is that perhaps I have a StateA that manages certain model and for that reason I use BlocA. Whenever certain event is added to BlocA, I also need to update StateB that is managed by BlocB. I do not want to do this within same bloc because those different states contain different data that might be unrelated. Perhaps I can then have BlocC that is used for specific part of application but certain event should also invoke events and state changes in BlocA and BlocB.

I am considering writing BlocA bloc like this:

class BlocA extends BlocBase<BlocAEvent, BlocAState>  {
  BlocA(BlocB blocB) : super(BlocAState()) {
    _blocB = blocB;
    _blocARepository = BlocARepository();
  };

  BlocARepository _blocARepository;

  @override
  BlocAState mapEventToState(BlocAEvent event) async* {
    if (event is BlocAEventOne) {
      yield state.copyWith(valueOne: event.value);
    } else if (event is BlocAEventTwo {
      // Get data related to BlocAState
      final data = await _blocARepository.fetchImportantData()
      // ! <-- I also need to fetch additional data but that is managed
      // by different bloc - BlocB
      _blocB.add(BlocBEventOne(id: data.id));
      yield state.copyWith(dataList: SomeModel.fromJSON(data));
    }
  }
}

and then just creating regular bloc BlocB like this:

class BlocB extends BlocBase<BlocBEvent, BlocBState>  {
  BlocB() : super(BlocBState()) {
    _blocBRepository = BlocBRepository();
  };

  BlocBRepository _blocBRepository;

  @override
  BlocBState mapEventToState(BlocBEvent event) async* {
    if (event is BlocBEventOne) {
      // Get data related to BlocBState
      final data = await _blocBRepository.fetchOtherData(event.id)
      yield state.copyWith(dataList: SomeOtherModel.fromJSON(data));
    }
  }
}

I am really unsure if this is correct approach as basically BlocA adds another event. But I am trying to do some reusable blocs and keep data more separate. I know I could also do _blocB.stream.listen in BlocA but that only gives me the state of the BlocB bloc. What I need is the ability to react to certain events.

Do you think that my approach is perhaps convoluted and using BlocObserver would perhaps be more appropriate? The problem with BlocObserver is that I am unsure how to use it properly from within Flutter app.


Solution

  • First of all, what you are trying to achieve is completely fine, but let's talk about the architecture a little bit.

    One option could be that BLoC B subscribes to BLoC A state changes and handles that accordingly. For instance, here a more specific BLoC subscribes to changes of a more generic one: https://github.com/felangel/bloc/blob/08200a6a03e37ce179cef10b65f34ddf6f43f936/examples/flutter_todos/lib/blocs/filtered_todos/filtered_todos_bloc.dart. For that, you would need to adjust the BLoC A state a bit (so you could identify this specific change/event) which could be not a way to go.

    Another thing you should consider is whether you want to tightly couple your BLoCs (BLoC B reference is passed to BLoC A via constructor in your example). For that, you can create some kind of mediator class that uses streams inside: BLoC A could publish an event to that mediator class sink and all the subscribers will receive it via exposed streams (in your case - BLoC B should subscribe to that stream) - so the communication there would be like BLoC A -> Mediator -> BLoC B. That's basically what Mediator/Observer OOP design pattern resolves. The advantage of it is that your BLoCs won't know anything about each other, multiple BLoCs could subscribe to multiple different event streams, meaning you could add more subscribers (BLoCs) to your events at any point.