在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 ...
}
)
发布于 2019-04-24 14:31:10
这实际上是你要求它做的行为。您正在产生一个状态(SignupVerificationEmailSentState
),然后立即将其更改回另一个状态SignupInitialState
。
当状态为is 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());
https://stackoverflow.com/questions/55830800
复制相似问题