Как вернуть Observable внешнему обещанию в Effects of NgRX? - PullRequest
0 голосов
/ 04 мая 2020

У меня вопрос о том, как вернуть Наблюдаемое внешнему обещанию. У меня в файле effect.ts следующее:

  @Effect()
  login$: Observable<Action> = this.actions$.pipe(
    ofType(UserActions.LOGIN),
    switchMap((action: UserActions.LoginAction) => {

      this.db.auth.signInWithEmailAndPassword(action.payload.email, action.payload.password).then(data => {
        this.db.auth.currentUser.getIdToken().then(reply => {
          return this.http.post(environment.apiUrl+'/api/login', { token: reply }).subscribe(response => {
              if (response['valid'] === 'true') {
                localStorage.setItem('token', JSON.stringify(reply));
                this.router.navigate(['dash']);
              }
            });
        });
      }).catch(err => {
        console.log('signIn failed: ' + err.message);
      });
    })
  );

Теперь моя цель - просто войти в FireBase, чтобы иметь возможность получить идентификационный токен и отправить запрос на отправку в серверную часть. Если ответ возвращается со свойством valid «true», перейдите к модулю «da sh».

Однако моя проблема:

Аргумент типа '(action: UserActions.LoginAction) => void' нельзя назначить параметру типа '(значение: LoginAction, index: number) => ObservableInput'. Тип 'void' нельзя назначить типу 'ObservableInput'.ts (2345)

Я полагаю, что это потому, что я поместил свой оператор return во внешнее обещание. Но я не знаю, как заставить его возвращаться правильно, потому что Firebase использует обещания, а NgRX использует Observables! Я пытаюсь вернуть Observable из обещания ... спасибо

Ответы [ 2 ]

1 голос
/ 04 мая 2020

Вы должны вернуть действие после вызова API

  @Effect()
  login$: Observable<Action> = this.actions$.pipe(
    ofType(UserActions.LOGIN),
    switchMap((action: UserActions.LoginAction) =>
      from(this.db.auth.signInWithEmailAndPassword(action.payload.email, action.payload.password)),
    ),
    switchMapTo(from(this.db.auth.currentUser.getIdToken())),
    switchMap(token => this.http.post(environment.apiUrl + '/api/login', { token })),
    tap((response: any) => {
      if (response.valid === 'true') {
        localStorage.setItem('token', JSON.stringify(token));
        this.router.navigate(['dash']);
      }
    }),
    map(response => UserActions.LoginSuccess({ response })),
    catchError(error => UserAction.LoginError({ error })),
  );
0 голосов
/ 04 мая 2020

Вы определенно на правильном пути. Я помню, как боролся с подобными вещами, когда впервые изучал Rx JS.

Несколько вещей, на которые я хотел бы обратить внимание:

  1. Эффекты должны возвращать действия. Вот что говорит сообщение об ошибке. Если вы не хотите, чтобы действие было возвращено, вы должны сделать это: @Effect({ dispatch: false }). В такой ситуации, однако, вам обязательно нужно отправить действие в конце, что-то вроде: «Пользователь успешно вошел в систему» ​​с токеном пользователя в качестве полезной нагрузки. Затем вы можете сохранить это в своем состоянии, используя редуктор. Но если все, что вам действительно нужно, это перейти к /dash после этого, а затем использовать параметр { dispatch: false }.
  2. Чтобы преобразовать Обещание в Observable, используйте функцию from внутри библиотеки rxjs , Таким образом, вы бы обернули все до того места, где вы обычно придерживаетесь функции then: from(this.db.auth.signInWithEmailAndPassword(action.payload.email, action.payload.password)).
  3. Избегайте switchMap для ситуаций такого типа. Это приведет к гоночным условиям. Вместо этого используйте exhaustMap. А затем используйте один для каждого обещания. Так что в конечном итоге это будет выглядеть примерно так:

    @Effect() login$: Observable<Action> = this.actions$.pipe( ofType(UserActions.LOGIN), exhaustMap((action: UserActions.LoginAction) => from(this.db.auth.signInWithEmailAndPassword(action.payload.email, action.payload.password)), exhaustMap(data => from(this.db.auth.currentUser.getIdToken()), exhaustMap(reply => { return this.http.post(environment.apiUrl+'/api/login', { token: reply }), map(response => { if (response['valid'] === 'true') { localStorage.setItem('token', JSON.stringify(reply)); this.router.navigate(['dash']); } }); }); }) }) );

...