ngrx ofType, @ngrx/effects
Solution 1
In a nutshell, when .ofType()
gets called, it subscribes to the source stream of actions and pushes matching actions to the resulting stream. So it is indeed called once.
If we look at the source code, we'll see that under the hood ofType
uses filter
operator of rxjs
library, meaning that this.action$.ofType(CREATE_TASK)
can be expanded to
this.action$.filter(action => action.type === CREATE_TASK)
Description of how filter
works can be found from rxjs
docs:
Similar to the well-known
Array.prototype.filter
method, this operator takes values from the source Observable, passes them through apredicate
function and only emits those values that yieldedtrue
.
It's worth noting that each of your effects takes an observable (this.action$
) as input and returns a new observable which is subscribed only once, when effects are initialized. That returned observable defines the way how actions from the input observable are transformed, but it does not affect the source observable itself.
In your example ofType()
method returns a new observable that "listens" to this.action$
observable and emits only actions that satisfy the condition action.type === CREATE_TASK
. Then goes the map
operator, it also returns a new observable which "listens" to the observable returned by ofType()
call and transforms each action it receives to a new value according to a projection function you pass. But all of those observables are created only once, upon initialization, and when you dispatch actions, they just "flow" through observables, get filtered and transformed.
You might also want to become more familiar with rxjs
. I would recommend you to check "You will learn RxJS" talk by André Staltz, it should give you an intuition of what observables are and how they work.
Solution 2
this.actions$ .ofType(CREATE_TASK) will call every time when your action get dispatched, after your reducer case get execute. like Redcucer
switch(action) {
case youractionsname.CREATE_TASK : {
// pure function logic here
}
}
First reducer will execute and then it will look into effect, if you have any effect who has type of 'CREATE_TASK'. In subscription pattern whatever you have subscribe that will be call back function and it will store in array under the hood based on condition. When you dispatch action based on condition that all function will call who meet the condition.
Solution 3
The point is that the ofType is not exported in Actions class inside the ngrx/effects so you can use it like following: 1- import ofType from ngrx/effects which would be
import { Injectable } from "@angular/core";
import { Effect, Actions, ofType } from "@ngrx/effects";
import * as omid from "@ngrx/effects";
import { of } from "rxjs";
import { map, switchMap, catchError } from "rxjs/operators";
@Injectable()
export class PizzasEffects {
constructor(
private actions$: Actions,
private pizzaService: frtomServices.PizzasService
) {}
@Effect()
LoadPizzas$ = this.actions$.pipe(
ofType(pizzaActions.LOAD_PIZZAS),
switchMap(() => {
return this.pizzaService.getPizzas().pipe(
map(pizzas => new pizzaActions.LoadPizzasSuccess(pizzas)),
catchError(error => of(new pizzaActions.LoadPizzasFail(error)))
);
})
);
}
Related videos on Youtube
Liam
Updated on June 04, 2022Comments
-
Liam almost 2 years
i try to understand how typeof effects work under the hood in ngrx, if i declare in my app module:
.... @NgModule({ imports: [ EffectsModule.forRoot([TodosEffectsService]) ], ....
and i write effect file sure:
@Effect() createTodos$ = this.actions$ .ofType(CREATE_TASK) .map(() => { console.log('called'); return { type: 'OTHER'}; }); @Effect() addTodos$ = this.actions$ .ofType(CREATE_TASK) .map(() => { console.log('called'); return { type: 'OTHER'}; });
i try to understand, now in run time i dispatch a action this.action$ is subscribed and every time execute ofType to match the type? or ofType once execute!?
if it called once, when i dispatch action how effects know every time witch effect to subscribe/execute?
thank all!
-
Liam almost 7 yearsthank you for response, so if i use store.dispatch({ type: CREAT_TASK, payload: payload}); every time i dispatch an action, this.action$ is execute all effects(returned observable) and check(filter) if type is correct?
-
Sergey Karavaev almost 7 yearsIf you have
N
epics each of which is using.ofType()
, then typically the predicateallowedTypes.some(type => type === action.type)
will be executedN
types, which is fine unless you have millions of epics registered or millions of allowed action types passed (and I guess it's not the case). If the filter does not accept an action, callbacks of the chained operators (e.g. the function you pass tomap()
) will not be executed. I would say that you should not be concerned with theofType()
performance, just don't create millions of epics : ) -
Liam almost 7 yearsyes of course, maybe i do not have a millions of allowed action types passed, but for big scale application, we have 30 epics for module, any small action like(checkd/uncheckd) every time all epics executed :\ i think they was can to save type as hash and call for the specific epic never mind i don't the ngrx contributor so .... :)
-
ebhh2001 over 5 years@SergeyKaravaev - sorry, but what is
epic
in this context? -
Sergey Karavaev over 5 years@ebhh2001, sorry for the confusion,
epic
is the term used in redux-observable middleware for redux. Inngrx-effects
epics are called "effects".