在 flutter 中从 EventSink 中删除错误

removing errors from EventSink in flutter

我从 flutter 应用程序中得到了奇怪的行为,试图解决这个问题两天...

  1. 如果我在热重启后立即尝试提交登录表单(空白字段)-> 错误:字段为空-> 然后我填写表单,我将再次尝试重新提交,一切正常。
  2. 如果我在没有提交空表单的情况下进行热重启并填写登录表单,提交按钮将永远不会将数据发送到服务器。由于现有的 EventSink 错误,由于某种原因在第一种情况下不会出现。

代码如下: 表单小部件:

@override
  Widget build(BuildContext context) {
    final FormBloc formBloc = FormProvider.of(context);

    Widget _emailField(FormBloc formBloc) {
      return StreamBuilder(
          stream: formBloc.email,
          builder: (context, AsyncSnapshot<String> snapshot) {
            return TextFormField(
              autofocus: false,
              keyboardType: TextInputType.emailAddress,
              onChanged: formBloc.changeEmail,


   Widget _passwordField(FormBloc formBloc) {
      return StreamBuilder(
          stream: formBloc.password,
          builder: (context, AsyncSnapshot<String> snapshot) {
            return TextFormField(
                autofocus: false,
                obscureText: !_passwordVisible,
                keyboardType: TextInputType.text,
                onChanged: formBloc.changePassword,

Formbloc:

class FormBloc with LoginValidationMixin {
  final _email = BehaviorSubject<String>();
  final _password = BehaviorSubject<String>();
  final _errorMessage = BehaviorSubject<String>();

  // getters
  Function(String) get changeEmail => _email.sink.add;
  Function(String) get changePassword => _password.sink.add;
  Function(String) get addError => _errorMessage.sink.add;

  // streams
  Stream<String> get email => _email.stream.transform(validatorEmail);
  Stream<String> get password => _password.stream.transform(validatorPassword);
  Stream<String> get errorMessage => _errorMessage.stream;

  Stream<bool> get submitValidForm => Rx.combineLatest3(
        email,
        password,
        errorMessage,
        (e, p, er) => true,
      );

  late AuthService authInfo;

  // login
  dynamic login(BuildContext context) async {
    authInfo = AuthService();

    final email = _email.valueOrNull;
    final password = _password.valueOrNull;

    if (email == null || password == null) {
      addError("Password or Email cannot be empty");
      return;
    }

    final response =
        await authInfo.login(email, password, this);
    if (response == null) {return;}
    final data = jsonDecode(response) as Map<String, dynamic>;

    if (data['status_code'] != 200) {
    } else {
      final tokens = data['tokens'];

      AuthService.setToken(
          tokens["access"], tokens["refresh"], data['client_id']);
      Navigator.pushNamed(context, '/home');
      return data;
    }
  }

验证


class LoginValidationMixin {
  static String get passwordPattern => "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{8,}";

  final validatorEmail = StreamTransformer<String, String>.fromHandlers(
    handleData: (email, sink) {
      sink.add(email);
      if (!EmailValidator.validate(email)) {
        sink.addError('Email should look like:'
            'welcome@itsy.ext\n');
      } else {
        sink.add(email);
      }
    },
  );

  final validatorPassword = StreamTransformer<String, String>.fromHandlers(
    handleData: (password, sink) {
      sink.add(password);
      if (!RegExp(passwordPattern).hasMatch(password)) {
        sink.addError('A hint, password should contain\n'
            'at least 8 characters\n'
            'at least 1 upper case character\n'
            'at least 1 upper case character\n'
            'at least 1 numerical character\n');
      } else {
        sink.add(password);
      }
    },
  );
}

登录按钮

Widget _loginButton(FormBloc formBloc) {
      return StreamBuilder<bool>(
          stream: formBloc.submitValidForm,
          builder: (context, AsyncSnapshot<bool> snapshot) {
            return Material(
              child: MaterialButton(
                onPressed: () {
                  if (snapshot.error != null) {
                    print(snapshot.error)  <<<< in the second scenario, here is always an error, even if filed validations have passed. While in the first scenario, this does work as expected.
                    return;
                  } else {
                    formBloc.login(context);
                  }
                },

所以,在第二种情况下,EventSink一直报错,按钮基本无法点击。但是,在第一种情况下,EventSink 工作正常,如果有错误则保留错误,如果添加了正确的值则清除它们。我应该怎么办?有没有办法清除 EventSink 错误?

这就是我解决这个问题的方法,首先我意识到流只会产生价值而不是存储。

pskink: EvenSink does not hold an error Next, I checked that

Stream<bool> get submitValidForm => Rx.combineLatest3(
        email,
        password,
        errorMessage, <<< this one is null in the case two, therefore my solution was to give it an initial value while handling email or password.
        (e, p, er) => true,
      );