моделирование и шаблон if / else внутри наблюдаемого конвейера rxjs - PullRequest
0 голосов
/ 30 марта 2019

У меня есть эпопея, где я слушаю поток действий, когда происходит действие 'AUTH_STATUS_CHECKED', переключаемся на новую наблюдаемую authState(app.auth()). Эта новая наблюдаемая говорит мне, аутентифицирован ли я или нет.

Если наблюдаемая авторизация возвращает пользователя, тогда отправьте действие 'SIGNED_IN' с пользователем в качестве полезной нагрузки.

Если пользователь не существует, тогда откажитесь от обещания app.auth().signInWithPopup(googleAuthProvider) и при получении ответа 'SIGNED_IN'.

Если есть какие-либо ошибки, поймайте их и сообщите мне в консоли.

основываясь на логике выше, я реализовал конвейер ниже

export const fetchAuthStatus = action$ =>
      action$.pipe(
        ofType('AUTH_STATUS_CHECKED'),
        switchMap(() =>
          authState(app.auth()).pipe(
            map(user =>
              user
                ? { type: 'SIGNED_IN', payload: user }
                : app
                    .auth()
                    .signInWithPopup(googleAuthProvider)
                    .then(user => ({ type: 'SIGNED_IN', payload: user }))
            ),
            catchError(error => console.log('problems signing in'))
          )
        )
      );

Это не работает, как ожидалось. Если пользователя нет, обещание будет выполнено, но оно не будет ждать ответа, и отправка не будет выполнена.

Я явно новичок в rxjs, и у меня возникли проблемы с этим разобраться. Я просмотрел документы и попытался использовать tap () и mergeMap (), но получаю ту же ошибку.

Любое руководство будет оценено.

Ответы [ 2 ]

1 голос
/ 30 марта 2019

Однако ваш код можно немного оптимизировать и рекомендую сделать это лучше, чего вам не хватает, так это того, что map ожидает простой объект, тогда как switchMap ожидает объект Promise или Observable.

const signIn = (authProvider) => app.auth().signInWithPopup(googleAuthProvider)
    .then(user => ({ type: 'SIGNED_IN', payload: user }));

export const fetchAuthStatus = action$ =>
    action$.pipe(
        ofType('AUTH_STATUS_CHECKED'),
        switchMap(() => authState(app.auth())),
        switchMap(user => user // <-- switchMap handle Promises or Observables
            ? of({ type: 'SIGNED_IN', payload: user }) // <-- returning an observable
            : signIn(googleAuthProvider) // <-- returning a promise
        ),
        catchError(error => console.log('problems signing in'))
    );

Примечания:

  • Не вкладывать оператор канала, стараться использовать как можно больше одного канала
  • Извлечь сложный метод из потока Rx
  • используйте оператор of для преобразования простого объекта в наблюдаемый
1 голос
/ 30 марта 2019

Если вам нужно подождать, пока какой-нибудь внутренний Observable / Promise завершится, вам нужно обернуть его, например. mergeMap или concatMap. Поскольку оба эти оператора требуют возврата Observable / Promise, вам нужно заключить действие в of(), чтобы превратить обычный объект в Observable:

import { of } from 'rxjs';
import { mergeMap } from 'rxjs/operators';

...
mergeMap(user => user
  ? of({ type: 'SIGNED_IN', payload: user })
  : app.auth().signInWithPopup(googleAuthProvider)...
)
...