Reputation: 251
I need to dispatch multiple actions after calling an API request in my effect. I'm using this code at the moment to dispatch one action after API request done:
changeStatus$ = createEffect(() =>
this.actions$.pipe(
ofType(fromJtDetail.changeStatus),
switchMap(action =>
this.jtDetailService.changeStatus(action.entity,action.jobTicketId).pipe(
map(res => fromJtDetail.statusChanged({changedStatus: action.entity.newStatus})),
catchError(error => EMPTY)
))));
It's important to dispatch more actions in this effect, can't write another effect for this.
Upvotes: 24
Views: 43167
Reputation: 2178
You can dispatch multiple actions using switchMap
+ of(
changeStatus$ = createEffect(() =>
this.actions$.pipe(
ofType(fromJtDetail.changeStatus),
switchMap(action =>
this.jtDetailService.changeStatus(action.entity,action.jobTicketId).pipe(
switchMap(res => of(
fromJtDetail.statusChanged({changedStatus: action.entity.newStatus}),
fromHere.doSmthAction(), // <-- additional action 1
fromThere.doSmthElseAction(), // <-- additional action 2
)),
catchError(error => EMPTY)
))));
EDIT:
Althought it can be done you should not do it.
Have a look at
no-multiple-actions-in-effects
EDIT2:
The initial link is from a now archived repo. The rule is still correct, it simply got moved to the NgRx core. Check here
no-multiple-actions-in-effects
Upvotes: 35
Reputation: 1
private _getAllEntreprises = createEffect(() =>
this.actions$.pipe(
ofType(EntrepriseActions.getAllEnterprises),
switchMap(({ query, page }) =>
this.service
.getAllEntreprises(page, query)
.pipe(
exhaustMap
((response) => {
return[
EntrepriseActions.getCurrentPage({current:response.current_page}),
EntrepriseActions.getTotalPages({ total: response.total_pages }),
EntrepriseActions.getAllEnterprisesCompleted({entreprises:response.enterprises}),
SettingsActions.loading({ loading: false }),
SettingsActions.successMsg({ message: response.message }),
]})
)
)
)
);
Upvotes: 0
Reputation: 3796
This Answer might help for other people seeking to solve multiple actions in effects.
As other people already answered,
You can dispatch multiple actions in one effects (return Array of actions, or use store to dispatch (this.store.dispatch(otherAction()) - BUT NO!
You SHOULD NOT dispatch multiple actions in one effects as it is anti-pattern (https://github.com/timdeschryver/eslint-plugin-ngrx/blob/main/docs/rules/no-multiple-actions-in-effects.md)
SOLUTION : Effects Chaining (One effects triggers another effects)
updateAPILoadingState$ = createEffect(()=>{
return this.action$.pipe(
ofType(getAPIAction), // <-- same action which below effects uses to update loading status
exhaustMap(()=>{
return updateLoadingState("LOADING")
})
)
})
getSomeInformationFromAPI$ = createEffect(()=>{
return this.action$.pipe(
ofType(getAPIAction), // <--- Listens to the Action
exhaustMap(()=>{
return this.apiService.getSomething().pipe(
map((apiResponse)=>
postAPISuccess(apiResponse)) // <-- trigger action to save the response
})
)
})
postAPISuccessEffect$ = createEffect(()=>{
return this.action$.pipe(
ofType(postAPISuccess), // <--- EFFECTS CHAIN : listen to the action which was triggered by above effect
exhaustMap(()=>{
return updateLoadingState("LOADED")
)
})
Upvotes: 5
Reputation: 15497
All of the answers here are correct, the "simple" answer and solution is to return an array of actions. However, this is a bad-practice, for more info see No Multiple Actions In Effects from the docs of NgRx ESLint.
Upvotes: 16
Reputation: 478
You can pass the array of actions into a switchMap like below:
switchMap(result => ([new Action1(result), new Action2(result)])
Upvotes: 3
Reputation: 3315
Of course other answer mentioned fairly that you can use the injected Store
reference or switchMap
to dispatch multiple actions, but it is worth noting that this is not considered a particularly good practice, as it can obscure intent in some cases, and make other effects (that are triggered as a result of this one) harder to reason about. You can find a detailed explanation of how to overcome this here, but briefly, an effect should only ever dispatch one and only one action, and then other effects (or reducer handlers) should additionally listen to that one action too. The link I provided also has examples of how to change to code to a more correct version.
Upvotes: 1