Возврат потока из функции

Я использую RiverPod для управления состоянием.

class SignInStateNotifier extends StateNotifier<SignInFormStates> {
  SignInStateNotifier(this._authFacade) : super(SignInFormStates.initial());

  final IAuthFacade _authFacade;

  void mapEventToState(SignInFormEvents signInFormEvents) {
    state = signInFormEvents.when(
        emailChanged: (value) => state.copyWith(
              emailAddress: EmailAddress(value),
              authFailureOrSuccess: none(),
            ),
        passwordChanged: (value) => state.copyWith(
              password: Password(value),
              authFailureOrSuccess: none(),
            ),
        signInWithEmailAndPasswordPressed: () async* {
          yield* _performActionOnAuthFacade(
              _authFacade.signInWithEmailAndPassword);
        });
  }

Я получаю сообщение об ошибке здесь

signInWithEmailAndPasswordPressed: () async* {
              yield* _performActionOnAuthFacade(
                  _authFacade.signInWithEmailAndPassword);
            });

Тип аргумента «Функция потока()» не может быть назначен типу параметра «Функция SignInFormStates()».

Моя функция __performActionOnAuthFacade

Stream<SignInFormStates> _performActionOnAuthFacade(
    Future<Either<AuthFailure, Unit>> Function({
      @required EmailAddress emailAddress,
      @required Password password,
    })
        forwardCall,
  ) async* {
    Either<AuthFailure, Unit> failureOrSuccess;
    if (state.emailAddress.isValid() && state.password.isValid()) {
      yield state.copyWith(
        isSubmitting: true,
        authFailureOrSuccess: none(),
      );
      failureOrSuccess = await _authFacade.registerWithEmailAndPassword(
          emailAddress: state.emailAddress, password: state.password);
    }
    yield state.copyWith(
        isSubmitting: false,
        showErrorMessage: true,
        authFailureOrSuccess: optionOf(failureOrSuccess));
  }

Пожалуйста, дайте решение, чтобы решить эту ошибку. Заранее спасибо.


person Pythonhub    schedule 23.01.2021    source источник


Ответы (2)


Если вы хотите сделать это с помощью StateNotifier, где нет необходимости использовать Stream для изменения состояния, вам нужно сделать что-то вроде этого:

class SignInFormStateNotifier extends StateNotifier<SignInFormState> {
  final IAuthFacade _authFacade;

  SignInFormStateNotifier(this._authFacade) : super(SignInFormState.initial());

  Future handleEvent(SignInFormEvent event) async {
    event.map(
      // email changed
      emailChanged: (event) {
        state = state.copyWith(
          emailAddress: EmailAddress(event.email),
          authFailureOrSuccessOption: none(),
        );
      },
      // password changed
      passwordChanged: (event) {
        state = state.copyWith(
          password: Password(event.password),
          authFailureOrSuccessOption: none(),
        );
      },
      // register with email and password
      registerWithEmailAndPassword: (event) async {
        await _performActionWithEmailAndPassword(
          _authFacade.registerWithEmailAndPassword,
        );
      },
      // sign in with email and password
      signInWithEmailAndPassword: (event) async {
        await _performActionWithEmailAndPassword(
          _authFacade.signInWithEmailAndPassword,
        );
      },
      // sign in with Google
      signInWithGoogle: (event) async {
        state = state.copyWith(
          isSubmitting: true,
          authFailureOrSuccessOption: none(),
        );
        final result = await _authFacade.signInWithGoogle();

        state = state.copyWith(
          isSubmitting: false,
          authFailureOrSuccessOption: some(result),
        );
      },
    );
  }

  Future _performActionWithEmailAndPassword(
    Future<Either<AuthFailure, Unit>> Function({
      @required EmailAddress emailAddress,
      @required Password password,
    })
        action,
  ) async {
    Either<AuthFailure, Unit> result;
    final isEmailValid = state.emailAddress.isValid();
    final isPasswordValid = state.password.isValid();

    if (isEmailValid && isPasswordValid) {
      state = state.copyWith(
        isSubmitting: true,
        authFailureOrSuccessOption: none(),
      );

      result = await action(
        emailAddress: state.emailAddress,
        password: state.password,
      );

      state = state.copyWith(
        authFailureOrSuccessOption: some(result),
      );
    }
    state = state.copyWith(
      isSubmitting: false,
      showErrorMessages: true,
      authFailureOrSuccessOption: optionOf(result),
    );
  }
}
person Viacheslav    schedule 25.01.2021
comment
Это работает!! Большое спасибо, @Viacheslav. Но не могли бы вы объяснить, почему это работает и по какой причине мы не хотим использовать поток и вместо этого используем Future? - person Pythonhub; 26.01.2021
comment
@PythonHub, это работает, потому что вы используете StateNotifier с StateNotifierProvider Riverpod, у меня нет времени объяснять, потому что мой английский не очень хорош. Но я рекомендую вам посмотреть видео Reso Coder Flutter StateNotifier + Riverpod Tutorial ссылка. Когда вы вызываете state = SomeState(...), Consumer, который слушает этот метод StateNotifierProvider из watch, запускает перестройку дерева виджетов. - person Viacheslav; 26.01.2021
comment
Спасибо большое, посмотрю урок - person Pythonhub; 26.01.2021
comment
@PythonHub, добро пожаловать. Удачи) - person Viacheslav; 26.01.2021

Я не знаю ваш класс SignInFormStates, но он не ожидает, что в signInWithEmailAndPasswordPressed вызовет функцию Stream, но, возможно, пустой voidCallback?

state = signInFormEvents.when(
        emailChanged: (value) => state.copyWith(
              emailAddress: EmailAddress(value),
              authFailureOrSuccess: none(),
            ),
        passwordChanged: (value) => state.copyWith(
              password: Password(value),
              authFailureOrSuccess: none(),
            ),
        signInWithEmailAndPasswordPressed: () => () async* {  //so a SignInFormStates Function() calls your stream function
          yield* _performActionOnAuthFacade(
              _authFacade.signInWithEmailAndPassword);
        });

Но все же есть шанс, что после этого он выдаст вам какую-то другую ошибку, сообщающую, что ваше состояние должно быть типа SignInFormStates, и вы передаете ему функцию потока, или, может быть, он фактически ждет завершения потока и возвращает новое полученное состояние, единственное, что нужно сделать, это попробовать и посмотреть, что произойдет

person EdwynZN    schedule 23.01.2021