4

在 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 ...
      }
)
4

1 回答 1

3

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

您正在调用raiseSnackBar()state is SignupVerificationEmailSentState,这是正确的,但是正如您所指出的,视图正在重建,因为您实际上是在没有足够的时间让用户看到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());
于 2019-04-24T14:31:10.227 回答