如何修复Flutter Cubit中emit(WaitingAuth)导致的状态丢失问题
Cubit表单状态丢失问题分析与解决
问题根源
你执行emit(const WaitingAuth())后请求参数为空,核心原因是:
WaitingAuth继承自AuthState,但它的构造函数const WaitingAuth() : super();没有传递任何参数,导致emit这个状态后,state中的所有表单字段(email、password等)都变为null。- 后续调用
_apiService.signUp时,你读取的是当前的state(也就是空的WaitingAuth状态),所以参数全部为空,触发服务器400错误。
解决方案
方案一:提前保存表单数据(快速修复)
在emit加载状态前,先把当前表单的所有字段值保存到局部变量里,后续请求用这些变量而不是直接读取state:
Future signUp() async { // 提前保存当前表单的所有字段值 final currentEmail = state.email ?? ""; final currentPassword = state.password ?? ""; final currentFirstName = state.firstName ?? ""; final currentLastName = state.lastName ?? ""; final currentGenderUuid = state.genderUuid ?? ""; final currentAgeGroupUuid = state.ageGroupUuid ?? ""; final currentCountryUuid = state.countryUuid ?? ""; emit(const WaitingAuth()); try { final data = await _apiService.signUp( email: currentEmail, password: currentPassword, firstName: currentFirstName, lastName: currentLastName, genderUuid: currentGenderUuid, ageGroupUuid: currentAgeGroupUuid, countryUuid: currentCountryUuid ); if (data['success']) { log(data.toString()); emit(const SuccessAutentification()); } } on DioError catch (ex) { log("cubit === ${ex.response!.data.toString()}"); // 请求失败后恢复表单状态,避免用户输入丢失 emit(AuthState( email: currentEmail, password: currentPassword, firstName: currentFirstName, lastName: currentLastName, genderUuid: currentGenderUuid, ageGroupUuid: currentAgeGroupUuid, countryUuid: currentCountryUuid )); } catch (e) { log(e.toString()); rethrow; } }
方案二:重构状态结构(长期推荐)
把表单数据状态和操作状态(加载、成功、错误)拆分,用密封类(sealed class)明确区分不同状态类型,逻辑更清晰:
1. 修改State文件
import 'package:equatable/equatable.dart'; sealed class AuthState extends Equatable {} // 专门存储表单数据的状态 class FormState extends AuthState { final String? email; final String? password; final String? firstName; final String? lastName; final String? genderUuid; final String? ageGroupUuid; final String? countryUuid; const FormState({ this.email, this.password, this.firstName, this.lastName, this.genderUuid, this.ageGroupUuid, this.countryUuid, }); FormState copyWith({ String? email, String? password, String? firstName, String? lastName, String? genderUuid, String? ageGroupUuid, String? countryUuid, }) { return FormState( email: email ?? this.email, password: password ?? this.password, firstName: firstName ?? this.firstName, lastName: lastName ?? this.lastName, genderUuid: genderUuid ?? this.genderUuid, ageGroupUuid: ageGroupUuid ?? this.ageGroupUuid, countryUuid: countryUuid ?? this.countryUuid, ); } @override List<Object?> get props => [email, password, firstName, lastName, genderUuid, ageGroupUuid, countryUuid]; } // 操作状态类,无需携带表单数据 class SuccessAuthentification extends AuthState { const SuccessAuthentification(); @override List<Object?> get props => []; } class ErrorAuthentification extends AuthState { const ErrorAuthentification(); @override List<Object?> get props => []; } class WaitingAuth extends AuthState { const WaitingAuth(); @override List<Object?> get props => []; }
2. 修改Cubit文件
class AuthCubit extends Cubit<AuthState> { AuthCubit() : super(const FormState( email: "", password: "", firstName: "", lastName: "", genderUuid: "", ageGroupUuid: "", countryUuid: "", )); final ApiService _apiService = ApiService(); // 更新表单字段时,先判断当前状态是FormState void setCountryUuid(String countryUuid) { if (state is FormState) { emit((state as FormState).copyWith(countryUuid: countryUuid)); } } void setFirstName(String firstName) { if (state is FormState) { emit((state as FormState).copyWith(firstName: firstName)); } } // 其他set方法(setEmail、setPassword等)同理修改 Future signUp() async { // 确保当前是表单状态,避免非预期状态下执行请求 if (state is! FormState) return; final currentForm = state as FormState; emit(const WaitingAuth()); try { final data = await _apiService.signUp( email: currentForm.email ?? "", password: currentForm.password ?? "", firstName: currentForm.firstName ?? "", lastName: currentForm.lastName ?? "", genderUuid: currentForm.genderUuid ?? "", ageGroupUuid: currentForm.ageGroupUuid ?? "", countryUuid: currentForm.countryUuid ?? "" ); if (data['success']) { log(data.toString()); emit(const SuccessAuthentification()); } } on DioError catch (ex) { log("cubit === ${ex.response!.data.toString()}"); // 请求失败后回到表单状态,保留用户输入 emit(currentForm); } catch (e) { log(e.toString()); rethrow; } } }
这种方式的优势在于状态职责清晰,不会出现“加载状态携带空表单数据”的问题,也更容易维护和扩展。
内容的提问来源于stack exchange,提问作者newbiras
相关产品推荐
相关产品推荐

