Можно ли дождаться вызова всех действий в операторе ofType, прежде чем вызывать следующий? - PullRequest
2 голосов
/ 14 февраля 2020

У меня есть массив избыточных действий, которые, когда были вызваны ВСЕ, я хочу вызвать другое действие в моем epi c. Действия в массиве изменчивы, динамические c. То, что я надеюсь найти, будет эквивалентно ofType оператору, работающему так:

ofType(FETCH_USER_PROFILE_SUCCESS && FETCH_USER_PREFERENCES_SUCCESS)

Когда оба действия были вызваны, другое вызывается дальше по трубе. , Конечно, оператор ofType не работает так. Для продолжения требуется только одно из действий.

Я читал, что combineLatest может быть решением, но мне не повезло. Ниже я представляю, как может выглядеть решение, но, очевидно, это не работает для меня. Буду признателен за любые предложения.

const actions = ['FETCH_USER_PROFILE_SUCCESS', 'FETCH_USER_PREFERENCES_SUCCESS'];

const asTypes = actions.map((action) => ofType(action);

const userEpic = (action$, state$) =>
  action$.pipe(
    combineLatest(asTypes);
    mergeMap(() =>
      of({
        type: 'SET_USER_READY'
      })
    )
  );

Исходя из приведенных ниже ответов:

Просто чтобы уяснить, что я имел в виду под Dynami c. Массив действий может включать в себя больше действий в зависимости от профиля пользователя (например, 'FETCH_USER_POSTS_SUCCESS'), по сути, неизвестное количество действий в зависимости от пользователя.

Таким образом, возможно генерировать это динамически:

zip( action$.pipe(ofType('FETCH_USER_PROFILE_SUCCESS')), action$.pipe(ofType('FETCH_USER_PREFERENCES_SUCCESS')), )

const actions = ['FETCH_USER_PROFILE_SUCCESS', 'FETCH_USER_PREFERENCES_SUCCESS', unknown number of more actions];

const actions = dynamic.forEach((action) => action$.pipe(ofType(action))

zip(
    actions
  )

Ответы [ 2 ]

0 голосов
/ 14 февраля 2020

Существует множество способов приблизиться к этому, потому что есть некоторые важные недостающие детали. Но я сделаю некоторые предположения:)

Самое большое, имеет ли значение порядок, в котором они прибывают. Если это не так, возможно, вам нужно использовать zip(). Он будет спаривать выбросы 1: 1 (фактически любое количество наблюдаемых, а не только два, например, 1: 1: 1 для трех и т. Д. c)

Даже в этом случае возникает вопрос о том, что вы хотите делать, если скорость, которую вы получаете действия варьируется между ними. Что произойдет, если вы получите FETCH_USER_PROFILE_SUCCESS в два раза быстрее, чем вы получили FETCH_USER_PREFERENCES_SUCCESS? Стоит ли продолжать их буферизовать? Вы их бросаете? Вы ошибаетесь?

Если их буферизация в порядке или вы иным образом предоставляете гарантии, что они всегда будут происходить с одинаковой скоростью, zip() работает.


Теперь, если вы хотите сделать Конечно, они приходят в некоторой последовательности, все становится еще сложнее. Скорее всего, у вас есть цепочка, использующая mergeMap, switchMap, выхлопная карта или concatMap. Принятие решения, которое снова зависит от того, что вы хотите сделать, если скорость, с которой вы получаете действия, не всегда одинакова.

import { zip } from 'rxjs';
import { map, take, switchMap } from 'rxjs/operators';
import { ofType } from 'redux-observable';

// Pair up the emissions 1:1 but without regard to the sequence
// in which they are received i.e. they can be in either order
const userEpic = (action$, state$) =>
  zip(
    action$.pipe(ofType('FETCH_USER_PROFILE_SUCCESS')),
    action$.pipe(ofType('FETCH_USER_PREFERENCES_SUCCESS')),
    // ...etc more observables
  ).pipe(
    map(() => ({
      type: 'SET_USER_READY'
    }))
  );


// FETCH_USER_PROFILE_SUCCESS must come before FETCH_USER_PREFERENCES_SUCCESS
// and if we receive another FETCH_USER_PROFILE_SUCCESS before we get
// the FETCH_USER_PREFERENCES_SUCCESS, start over again (switchMap)
const userEpic = (action$, state$) =>
  action$.pipe(
    ofType('FETCH_USER_PROFILE_SUCCESS'),
    switchMap(() =>
      action$.pipe(
        ofType('FETCH_USER_PREFERENCES_SUCCESS'),
        take(1) // important! we only want to wait for one
      )
    ),
    map(() => ({
      type: 'SET_USER_READY'
    }))
  )

Действия в массиве изменчивы, динамические c

Непонятно, как вы хотите, чтобы они изменились, поэтому я не включил механизм для этого.

-

Здесь также есть похожий вопрос: { ссылка }

0 голосов
/ 14 февраля 2020

почему бы не сделать одно общее действие, например executeAllActions, и внутри полезной нагрузки этого действия вы передаете массив, который содержит все ссылки для всех действий, которые вы хотите, например

executeAllActions = {
    type: 'exectueAllActions',
    actionsList: [ fetchCategories, fetchProducts, ...],
}

, затем вы слушаете это действие

this.actions$.pipe(
   ofType(executeAllActions),
   concatMap(action => [ ...actions.actionsList ])
)

, где мы использовали concatMap, чтобы вернуть список актоинов, которые все будут выполнены.

I wi sh Я могу попробовать эту идею сейчас, но я думаю, что это как-то возможно , Если это работает для вас, пожалуйста, дайте мне знать.

...