Emitting states from a bloc using bloc.emit
Asked Answered
E

2

6

I'm building a phone authentication ui (OTP) using firebase_auth library with BLoC pattern (a bit of an overkill for this ui, but the whole project is in BLoC, so). I'm processing the authentication within the BLoC, as such:


  @override
  Stream<PhoneAuthState> mapEventToState(PhoneAuthEvent event) async* {
    ....
    else if(event is PhoneNumberSubmittedEvent) yield* _handlePhoneNumberSubmittedEvent(event);
    ....
  }

  Stream<PhoneAuthState> _handlePhoneNumberSubmittedEvent(PhoneNumberSubmittedEvent event) async*{
      yield SendingCodeState();

      await Firebase.initializeApp();
      var firebaseAuth = FirebaseAuth.instance;

      await firebaseAuth.verifyPhoneNumber(
        phoneNumber: _buildPhoneNumber(),
        timeout: Duration(seconds: 0),
        verificationCompleted: (firebaseUser) {},
        codeAutoRetrievalTimeout: (String verificationId) {},


        // Relevant code

        codeSent: (id, [forceResendingToken]) =>
          emit(_codeSentState(id, forceResendingToken)),

        verificationFailed: (error) =>
          emit(_verificationFailedState(error)),
      );
  }

Because the results of my _codeSentState and _verificationFailedState functions cannot be yielded from within the handlePhoneNumberSubmittedEvent method, I used emit (which is actually working fine).

However, as I was looking through BLoC docs, I found that emit is @protected, and the docs stating:

[emit] should never be used outside of tests.

So I have three questions:

  1. Why shouldn't emit be used outside of tests?
  2. Is there an alternative to emit? (other than yielding in response to events in mapEventToState)
  3. Is there a way to yield the result of a function that is passed as a parameter to a method/constructor call? (in my case, is there a way to yield the results of _codeSentState and/or _verificationFailedState that are called within firebaseAuth.verifyPhoneNumber.codeSent and firebaseAuth.verifyPhoneNumber.verificationFailed respectively?)
Estus answered 18/10, 2020 at 7:54 Comment(0)
E
4

In flutter_bloc version 8.0.0, this issue was resolved. The method mapEventToState was replaced with the more efficient on<Event> to respond to events. on method provides an emitter as a parameter to its callback, which can be used to emit states as needed. In other words, the code I mentioned in OP can now be written as follows

// constructor
MyBloc() : super(MyInitialState) {
  on<PhoneNumberSubmittedEvent>((event, emit) async {
      emit(SendingCodeState());

      await Firebase.initializeApp();
      var firebaseAuth = FirebaseAuth.instance;

      await firebaseAuth.verifyPhoneNumber(
        phoneNumber: _buildPhoneNumber(),
        timeout: Duration(seconds: 0),
        verificationCompleted: (firebaseUser) {},
        codeAutoRetrievalTimeout: (String verificationId) {},

        codeSent: (id, [forceResendingToken]) =>
          emit(_codeSentState(id, forceResendingToken)),

        verificationFailed: (error) =>
          emit(_verificationFailedState(error)),
      );
  });
}
Estus answered 14/2, 2022 at 7:26 Comment(1)
That's fine if emit is inside the on<Event>{} but how do I trigger the event outside of that? Like in a different controller where I don't have the context. I asked the question here: #72029615Greaten
B
2

migrate to the new version of the bloc (>=6.0.0) wich bloc is integrated with cubit and the best practice is to bloc class extends the Cubit class and using the emit function to yield new state read more on the bloc pub page : https://pub.dev/packages/flutter_bloc

Update

as I mentioned in the new version author of the bloc migrated the bloc with the cubit package which adds an alternative and simplified capability to control the state of the application if your bloc class is extending the bloc base class so you should use (yilding state) pattern for controling the state but if your bloc extends cubit you can directly use the emit method to control the state you can read about it in the documentation here is the link: http://github.com/felangel/bloc/blob/master/packages/bloc/README.md

Brinkmanship answered 18/10, 2020 at 8:10 Comment(4)
I have narrowed down my question to three points, and your answer provides an answer to none of them. It only points at the documentation and explains how flutter_bloc is built.Estus
@Skullz I am saying your question is related to the previous versions of the bloc and in the new version it is not true and u can use the emit function inside bloc by default and it is not bounded just for using in the testsBrinkmanship
I already have the latest version. If you check their official documentation, it says [emit] should never be used outside of tests. They do expose the method, but only for testing.Estus
@Skullz as I mentioned in my answer in the new version author of the bloc migrated the bloc with the cubit package which adds an alternative and simplified capability to control the state of the application if your bloc class is extending bloc base class so you should use (yilding state) pattern for controling the state but if your bloc extends cubit you can directly use the emit method to control the state u can read about it in the documentation here is the link : github.com/felangel/bloc/blob/master/packages/bloc/README.mdBrinkmanship

© 2022 - 2024 — McMap. All rights reserved.