Как выполнить несколько действий в одном эпосе, используя наблюдаемую редуксу? - PullRequest
1 голос
/ 23 мая 2019

Я новичок в наблюдаемой rxjs / redux и хочу сделать две вещи:

1) улучшите эту эпопею, чтобы она стала более идиоматичной

2) отправить два действия из одного эпоса

Большинство примеров, которые я вижу, предполагают, что библиотека api будет генерировать исключение при сбое выборки, но я разработал мой, чтобы быть немного более предсказуемым, и с типами объединения Typescript я вынужден проверить ok: boolean Значение, прежде чем я смогу распаковать результаты, поэтому понимание того, как это сделать в rxjs, было немного сложнее.

Какой лучший способ улучшить следующее? Если запрос выполнен успешно, я хотел бы выдать как действие об успешном выполнении (имеется в виду, что пользователь авторизован), так и действие «получить учетную запись», которое является отдельным действием, поскольку в некоторых случаях может потребоваться получить учетную запись извне просто «войти». Любая помощь будет принята с благодарностью!

const authorizeEpic: Epic<ActionTypes, ActionTypes, RootState> = action$ =>
  action$.pipe(
    filter(isActionOf(actions.attemptLogin.request)),
    switchMap(async val => {
      if (!val.payload) {
        try {
          const token: Auth.Token = JSON.parse(
            localStorage.getItem(LOCAL_STORAGE_KEY) || ""
          );
          if (!token) {
            throw new Error();
          }
          return actions.attemptLogin.success({
            token
          });
        } catch (e) {
          return actions.attemptLogin.failure({
            error: {
              title: "Unable to decode JWT"
            }
          });
        }
      }

      const resp = await Auth.passwordGrant(
        {
          email: val.payload.email,
          password: val.payload.password,
          totp_passcode: ""
        },
        {
          url: "localhost:8088",
          noVersion: true,
          useHttp: true
        }
      );

      if (resp.ok) {
        return [
          actions.attemptLogin.success({
            token: resp.value
          })
          // EMIT action 2, etc...
        ];
      }

      return actions.attemptLogin.failure(resp);
    })
  );

Ответы [ 2 ]

1 голос
/ 24 мая 2019

Документы для switchMap указывают, что функция проекта (лямбда в вашем примере) может возвращать следующее:

type ObservableInput<T> = SubscribableOrPromise<T> | ArrayLike<T> | Iterable<T>

Когда возвращается Promise<T>, разрешенноезначение просто излучается.В вашем примере, если вы вернете массив из области действия async, массив будет отправлен непосредственно в хранилище Redux.Предполагая, что у вас нет специальной установки промежуточного программного обеспечения Redux для обработки массива событий, скорее всего, это не то, что вам нужно.Вместо этого я бы рекомендовал возвращать наблюдаемые в функции проекта.Это небольшое изменение вашего примера:

const authorizeEpic: Epic<ActionTypes, ActionTypes, RootState> = action$ =>
  action$.pipe(
    filter(isActionOf(actions.attemptLogin.request)), // or `ofType` from 'redux-observable'?
    switchMap(action => {
      if (action.payload) {
        try {
          const token: Auth.Token = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY) || "")
          if (!token) {
            throw new Error()
          }

          // return an observable that emits a single action...
          return of(actions.attemptLogin.success({
            token
          }))
        } catch (e) {
          // return an observable that emits a single action...
          return of(actions.attemptLogin.failure({
            error: {
              title: "Unable to decode JWT"
            }
          }))
        }
      }

      // return an observable that eventually emits one or more actions...
      return from(Auth.passwordGrant(
        {
          email: val.payload.email,
          password: val.payload.password,
          totp_passcode: ""
        },
        {
          url: "localhost:8088",
          noVersion: true,
          useHttp: true
        }
      )).pipe(
        mergeMap(response => response.ok
          ? of(
            actions.attemptLogin.success({ token: resp.value }),
            // action 2, etc...
          )
          : of(actions.attemptLogin.failure(resp))
        ),
      )
    }),
  )

У меня нет ваших определений типов TypeScript, поэтому я не могу убедиться, что приведенный выше пример работает точно.Тем не менее, у меня был довольно хороший успех с более свежими версиями TypeScript, RxJS и redux-observable.Ничто не выделяется из вышесказанного, что заставляет меня думать, что вы должны столкнуться с какими-либо проблемами.

0 голосов
/ 23 мая 2019

Вы можете архивировать свои действия и возвращать их.

zip(actions.attemptLogin.success({
            token: resp.value
          })
          // EMIT action 2, etc...

Так что теперь оба ваших действия будут называться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...