Отличный вопрос. Важным моментом является то, что action$
— это горячий/многоадресный поток всех действий по мере их отправки (это тема). Поскольку жарко, мы можем комбинировать его несколько раз, и все они будут слушать один и тот же поток действий.
// uses switchMap so if another PAGINATION_CLICKED comes in
// before FETCH_SUCCESS we start over
action$
.ofType(PAGINATION_CLICKED)
.switchMap(() =>
action$.ofType(FETCH_SUCCESS)
.take(1) // <-------------------- very important!
.map(() => analyticsAction())
.takeUntil(action$.ofType(FETCH_ERROR))
);
Поэтому каждый раз, когда мы получаем PAGINATION_CLICKED
, мы начинаем слушать эту внутреннюю цепочку Observable, которая прослушивает один FETCH_SUCCESS
. Важно иметь этот .take(1)
, потому что в противном случае мы будем продолжать прослушивать более одного FETCH_SUCCESS
, что может привести к странным ошибкам, и даже если это не так, обычно рекомендуется брать только то, что вам нужно.
Мы используем takeUntil
, чтобы отменить ожидание FETCH_SUCCESS
, если сначала получим FETCH_ERROR
.
В качестве бонуса, если вы решите, что хотите также выполнить некоторые аналитические действия на основе ошибки, не только начать заново, вы можете использовать race
для действительной гонки между двумя потоками. Выигрывает тот, кто излучает первым; другой отписался.
action$
.ofType(PAGINATION_CLICKED)
.switchMap(() =>
Observable.race(
action$.ofType(FETCH_SUCCESS)
.take(1)
.map(() => analyticsAction()),
action$.ofType(FETCH_ERROR)
.take(1)
.map(() => someOtherAnalyticsAction())
)
);
Вот то же самое, но с использованием race
в качестве оператора экземпляра вместо статического. Это стилистическое предпочтение, которое вы можете выбрать. Они оба делают одно и то же. Используйте тот, который вам более понятен.
action$
.ofType(PAGINATION_CLICKED)
.switchMap(() =>
action$.ofType(FETCH_SUCCESS)
.map(() => analyticsAction())
.race(
action$.ofType(FETCH_ERROR)
.map(() => someOtherAnalyticsAction())
)
.take(1)
);
person
jayphelps
schedule
07.08.2017