ngrx ofType, @ngrx/effects

Liam picture Liam · Aug 3, 2017 · Viewed 8.7k times · Source

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!

Answer

Sergey Karavaev picture Sergey Karavaev · Aug 7, 2017

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 a predicate function and only emits those values that yielded true.

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.