使用 bloc.emit 从一个 bloc 中发射状态

Emitting states from a bloc using bloc.emit

我正在使用具有 BLoC 模式的 firebase_auth 库进行 phone 身份验证 ui (OTP)(对于这个 ui,但整个项目都在 BLoC 中,所以)。我正在 BLoC 中处理身份验证,因此:


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

因为我的 _codeSentState_verificationFailedState 函数的结果无法从 handlePhoneNumberSubmittedEvent 方法中产生,所以我使用了 emit(实际上工作正常)。

然而,当我浏览 BLoC 文档时,我发现 emit@protected,并且文档说明:

[emit] should never be used outside of tests.

所以我有三个问题:

  1. 为什么 emit 不能在测试之外使用?
  2. 是否有 emit 的替代方案? (除了响应 mapEventToState 中的事件而屈服)
  3. 有没有办法 yield 作为参数传递给 method/constructor 调用的函数的结果? (在我的例子中,有没有办法 yield 分别在 firebaseAuth.verifyPhoneNumber.codeSentfirebaseAuth.verifyPhoneNumber.verificationFailed 中调用的 _codeSentState and/or _verificationFailedState 的结果? )

迁移到新版本的 bloc (>=6.0.0) wich bloc 与 cubit 集成,最佳实践是 bloc class 扩展 Cubit class 并使用 emit产生新状态的功能 在 bloc pub 页面上阅读更多内容:https://pub.dev/packages/flutter_bloc

更新

正如我在新版本中提到的,bloc 的作者使用 cubit 包迁移了 bloc,它添加了一种替代和简化的功能来控制应用程序的状态 如果你的 bloc class 正在扩展 bloc base class 所以你应该使用 (yilding state) 模式来控制状态但是如果你的 bloc 扩展了 cubit 你可以直接使用 emit 方法来控制你可以的状态在此处的文档中阅读它是 link:http://github.com/felangel/bloc/blob/master/packages/bloc/README.md

flutter_bloc 版本 8.0.0 中,此问题已解决。方法 mapEventToState 被替换为更有效的 on<Event> 来响应事件。 on 方法提供一个 emitter 作为其回调的参数,可用于根据需要发出状态。也就是说,我在OP中提到的代码现在可以这样写了

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