Flutter Bloc二次点击提交按钮无法触发加载弹窗问题
问题根因
- Bloc默认基于Equatable的props判断状态是否相同,你的
Loading状态props返回空数组,前后两次Loading状态会被判定为完全相同,不会触发BlocListener的回调 - 用户手动关闭加载弹窗时,仅关闭了弹窗路由,没有同步更新Bloc的状态,Bloc当前状态会一直停留在
Loading,第二次提交时再次yield的Loading会被去重,不会触发弹窗显示 - 额外隐患:
Login事件重写的props返回空数组,会导致相同参数的重复提交事件被Bloc直接忽略
修复方案
- 修正事件类的props定义
class Login extends SignInEvent{ @override List<Object?> get props => [userName, password, pin]; // 修正props返回值 final String userName; final String password; final String pin; Login(this.userName,this.password,this.pin) : super([userName,password,pin]); }
- 新增重置状态的事件,处理用户手动关闭弹窗的场景
首先在事件类新增重置事件:
class ResetSignInState extends SignInEvent { @override List<Object?> get props => []; }
在Bloc逻辑中添加重置事件的处理逻辑:
if (event is ResetSignInState) { yield SignInInitial(); }
- 给加载弹窗添加关闭回调,关闭时同步重置Bloc状态
如果你的弹窗工具类支持关闭回调,直接修改UI层BlocListener中的弹窗调用逻辑:
if(state is Loading){ loading.showAlertDialog( context, // 手动关闭弹窗时触发,重置Bloc状态到初始值 onDismiss: () => context.read<SignInBloc>().add(ResetSignInState()), ); }
如果弹窗工具类没有内置关闭回调,可以通过showDialog的then回调监听关闭事件:
showDialog( context: context, builder: (context) => const LoadingAlert(), ).then((_) { // 弹窗关闭时触发 context.read<SignInBloc>().add(ResetSignInState()); });
- 优化Bloc请求逻辑,避免异步操作返回后状态异常
if (event is Login) { // 先切回初始状态,保证Loading状态变更能被监听到 yield SignInInitial(); yield Loading(); final login = await loginUser(event.userName, event.password, event.pin); // 仅当当前仍为Loading状态时返回结果,避免用户已取消后还触发后续逻辑 if (state is Loading) { yield Loaded(login); } }
内容的提问来源于stack exchange,提问作者Vincent Agbo
相关产品推荐
相关产品推荐

