在Dart(Flutter)中将两个“yield”放在一起,只有第二个会被执行

4
在Flutter中,我正在使用BLoC模式和Firebase创建一个登录/注册页面。注册用户后,我会发送验证电子邮件并将状态更改为“VerificationEmailSentState”(以便在PageView中显示SnackBar并切换到登录页面),然后再将其重新更改为初始状态(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 ...
      }
)
1个回答

3

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

当状态是SignupVerificationEmailSentState 时,你调用raiseSnackBar()是正确的,但正如你所指出的那样,视图被重建了,因为你实际上没有足够的时间让用户看到 SnackBar.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());

谢谢你的回答。 我唯一的担心是我不确定1秒是否足够,因为我认为这取决于硬件以及执行BlocBuilder内所有语句所需的时间。 - Amer Alahmar
@AmerAlahmar 我已经编辑了我的答案,并提供了一个完全符合你要求的示例。它会显示 SnackBar,当其被关闭时,它将调用 bloc.revertToSignupInitialState() 方法,该方法可以是一个返回到该状态的方法。 - Miguel Ruivo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接