hman_codes
hman_codes

Reputation: 888

Emitting states from a bloc using bloc.emit

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?)

Upvotes: 6

Views: 12725

Answers (2)

hman_codes
hman_codes

Reputation: 888

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)),
      );
  });
}

Upvotes: 4

Amir Hossein Mirzaei
Amir Hossein Mirzaei

Reputation: 2375

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

Upvotes: 2

Related Questions