在 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 ...
}
)
最佳答案
这实际上就是您要求它执行的行为。您正在生成一个状态 (SignupVerificationEmailSentState
),然后立即将其更改回另一个状态 SignupInitialState
。
当状态 为 SignupVerificationEmailSentState
时,您正在调用 raiseSnackBar()
,这是正确的,但是正如您指出的那样,正在重建 View ,因为您实际上正在恢复它返回时没有足够的时间让用户看到 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());
关于flutter - 在 Dart (Flutter) 中将两个 "yield"并排放置,只有第二个被执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55830800/