Отправлять несколько действий одним действием
Я хотел бы выделить два действия одним эффектом.
В настоящее время я должен объявить два эффекта для достижения этого:
// first effect
@Effect() action1$ = this.actions$
.ofType(CoreActionTypes.MY_ACTION)
.map(res => {
return { type: "ACTION_ONE"}
})
.catch(() => Observable.of({
type: CoreActionTypes.MY_ACTION_FAILED
}));
// second effect
@Effect() action2$ = this.actions$
.ofType(CoreActionTypes.MY_ACTION)
.map(res => {
return { type: "ACTION_TWO"}
})
.catch(() => Observable.of({
type: CoreActionTypes.MY_ACTION_FAILED
}));
Возможно ли иметь одно действие, быть источником двух действий с помощью одного эффекта?
Ответы
Ответ 1
@Effect()
loadInitConfig$ = this.actions$
.ofType(layout.ActionTypes.LOAD_INIT_CONFIGURATION)
.map<Action, void>(toPayload)
.switchMap(() =>
this.settingsService
.loadInitConfiguration()
.mergeMap((data: any) => [
new layout.LoadInitConfigurationCompleteAction(data.settings),
new meetup.LoadInitGeolocationCompleteAction(data.geolocation)
])
.catch(error =>
Observable.of(
new layout.LoadInitConfigurationFailAction({
error
})
)
)
);
Ответ 2
Вы можете использовать switchMap
и Observable.of
.
@Effect({ dispatch: true }) action$ = this.actions$
.ofType(CoreActionTypes.MY_ACTION)
.switchMap(() => Observable.of(
// subscribers will be notified
{type: 'ACTION_ONE'} ,
// subscribers will be notified (again ...)
{type: 'ACTION_TWO'}
))
.catch(() => Observable.of({
type: CoreActionTypes.MY_ACTION_FAILED
}));
Эффективность:
Вместо того, чтобы отправлять много действий, которые будут запускать все подписчики столько раз, сколько вы отправляете, вы можете взглянуть на redux-batched-actions.
Это позволяет вам предупреждать своих подписчиков только в том случае, если все эти несколько действий были применены к хранилищу.
Например:
@Effect({ dispatch: true }) action$ = this.actions$
.ofType(CoreActionTypes.MY_ACTION)
// subscribers will be notified only once, no matter how many actions you have
// not between every action
.map(() => batchActions([
doThing(),
doOther()
]))
.catch(() => Observable.of({
type: CoreActionTypes.MY_ACTION_FAILED
}));
Ответ 3
Вы можете выбрать mergeMap
для async или concatMap
для синхронизации
@Effect() action$ = this.actions$
.ofType(CoreActionTypes.MY_ACTION)
.mergeMap(() => Observable.from([{type: "ACTION_ONE"} , {type: "ACTION_TWO"}]))
.catch(() => Observable.of({
type: CoreActionTypes.MY_ACTION_FAILED
}));
Ответ 4
вы также можете использовать .do() и store.next()
do позволяет присоединить обратный вызов наблюдаемому, не затрагивая других операторов/изменяя наблюдаемый
например.
@Effect() action1$ = this.actions$
.ofType(CoreActionTypes.MY_ACTION)
.do(myaction => this.store.next( {type: 'ACTION_ONE'} ))
.switchMap((myaction) => Observable.of(
{type: 'ACTION_TWO'}
))
.catch(() => Observable.of({
type: CoreActionTypes.MY_ACTION_FAILED
}));
(вам понадобится ссылка на хранилище в вашем классе эффектов)
Ответ 5
Если кому-то интересно, как смешать простые действия с действиями из Observables.
Я застрял с той же задачей, но с небольшой разницей: мне нужно было отправить два действия, второе после вызова API, что сделало его наблюдаемым. Что-то вроде:
-
action1
- это просто действие: {type: 'ACTION_ONE'}
-
action2
- это вызов API, сопоставленный с action: Observable<{type: 'ACTION_TWO'}>
Следующий код решил мою проблему:
@Effect() action$ = this.actions$.pipe(
ofType(CoreActionTypes.MY_ACTION),
mergeMap(res =>
// in order to dispatch actions in provided order
concat(
of(action1),
action2
)
),
catchError(() => Observable.of({
type: CoreActionTypes.MY_ACTION_FAILED
}))
);
Concat Doc's