【问题标题】:Placing two "yield"s next to each other in Dart (Flutter), only the second get executed在 Dart (Flutter) 中将两个“yield”并排放置,只有第二个被执行
【发布时间】:2019-09-13 19:04:48
【问题描述】:

在 Flutter 中,我正在使用 BLoC 模式和 Firebase 制作登录/注册页面。注册用户后,我正在发送验证电子邮件并将状态更改为“VerificationEmailSentState”(这样我就可以显示 SnackBar 并在 PageView 中切换到登录页面),然后将其重新更改为初始状态(InitialState)。问题是它直接跳转到 InitialState 而没有经过 VerificationEmailSentState 因此没有显示 SnackBar 或切换到登录页面!

当我调试代码时,我发现它实际上将状态更改为 (VerificationEmailSentState),但随后立即将其更改回 InitialState,因此 BlocBuilder 中的代码不会被执行,因为当我被中断(重新构建)时我将状态更改为 InitialState。为了确保,我在第一次更改状态后延迟了 1 秒并且它起作用了(出现了 SnackBar)。

问题是为什么会这样?延迟状态的第二次变化是个好主意吗?如果没有,没有它如何让它工作?

//SignupBloc
await user.sendEmailVerification();
yield SignupVerificationEmailSentState();
await Future.delayed(Duration(seconds: 1)); //Will not work without it.
yield SignupInitialState();
//LoginSignupPage
BlocBuilder<SignupEvent, SignupState>(
      bloc: _signupBloc,
      builder: (BuildContext context, SignupState state) {
        if (state is SignupVerificationEmailSentState) {
          print("About to show SnackBar");//Printed only with delay
          raiseSnackBar();
          swtichToLogin();
        }
        return ...
      }
)

【问题讨论】:

    标签: flutter yield bloc


    【解决方案1】:

    这实际上是您要求它执行的行为。您正在生成一个状态 (SignupVerificationEmailSentState),然后立即将其更改回另一个状态 SignupInitialState

    当状态为is SignupVerificationEmailSentState 时,您正在调用raiseSnackBar(),这是正确的,但是,正如您所指出的,正在重建视图,因为您实际上是在将其还原回来而没有足够的时间让用户看到@ 987654325@。 await Future.delayed(Duration(seconds: 1)) 实际上是在给它一秒钟的时间来展示它。

    这不是一个“坏方法”,它取决于您的应用程序的流程以及您实际想要实现的目标。但是,我宁愿这样做

    Future.delayed(Duration(seconds: 1)).then((_) => yield SignupInitialState());
    

    这不会阻止任何其他指令在该方法调用中在该指令之后运行,假设您可能有一些指令。如果你不这样做,那很好。

    如果您想确保它仅在 SnackBar 显示 1 秒后恢复到初始状态,请删除这两行:

    await Future.delayed(Duration(seconds: 1)); //Will not work without it.
    yield SignupInitialState();
    

    你可以这样做:

      Scaffold.of(context)
                .showSnackBar(
                  SnackBar(
                    content: Text('Something...'),
                    duration: Duration(seconds: 1),
                  ),
                )
                .closed
                .then((_) => bloc.revertToSignupInitialState());
    

    【讨论】:

    • 感谢您的回答。我唯一担心的是我不能 100% 确定 1 秒是否足够,因为我认为这取决于硬件以及执行 BlocBuilder 中的所有语句需要多少时间。
    • @AmerAlahmar 我已经用一个完全符合您要求的示例编辑了我的答案。它显示SnackBar,然后,当它被解除(关闭)时,它将调用一个`bloc.revertToSignupInitialState()`,它可以是一个返回到该状态的方法。
    猜你喜欢
    • 2020-01-28
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    相关资源
    最近更新 更多