You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 23:25:20