Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ngrx Effects: Are actions dispatched by one effect processed immediately by other effects?

I have an Angular (2) app with four ngrx actions:

  • START
    • Not processed by the reducer (no state change)
    • ngrx Effect calls an async task and maps to SUCCESS or ERROR
  • SUCCESS
    • Processed by the reducer
    • ngrx Effect maps to ADVANCE
  • ADVANCE
    • Not processed by the reducer
    • ngrx Effect navigates to a different route
  • ERROR
    • Processed by the reducer
    • No Effect

The problem is that the Effect that catches ADVANCE seems to run before the reducer that processes SUCCESS

Here's the Effects code:

@Effect() start$ = this.actions$
    .ofType('START')
    .map(toPayload)
    .switchMap(input => doAsyncTask(input)
        .map(result => ({type: 'SUCCESS', payload: result}))
        .catch(error => ({type: 'ERROR', payload: error})));

@Effect() success$ = this.actions$
    .ofType('SUCCESS')
    .map(() => ({type: 'ADVANCE'}));

@Effect({dispatch: false}) advance$ = this.actions$
    .ofType('ADVANCE')
    .withLatestFrom(this.store$.select(state => state.route))
    .map(action_route => action_route[1])
    .do(route => this.router.navigate([route.foo.bar]));

The error that I am getting is Cannot read property 'bar' of null. The property foo is set by the reducer that processes SUCCESS.

If I add a delay to the SUCCESS effect, it all works nicely:

@Effect() success$ = this.actions$
    .ofType('SUCCESS')
    .delay(1)
    .map(() => ({type: 'ADVANCE'}));

But having to add this delay doesn't make sense to me.

I added console.log statements everywhere and the output looks like this:

  1. SUCCESS effect
  2. ADVANCE effect (showing route.foo === null)
  3. SUCCESS reducer (showing route.foo === something)
  4. Error

I expected the SUCCESS effect and the SUCCESS reducer to run before the ADVANCE effect.

Am I doing something wrong?

Is it incorrect to expect that actions are processed by the reducers in the same order that they are dispatched?


Versions:

  • @angular/cli: 1.0.0-beta.32.3
  • node: 7.5.0
  • os: darwin x64
  • @angular/common: 2.4.7
  • @angular/compiler: 2.4.7
  • @angular/core: 2.4.7
  • @angular/forms: 2.4.7
  • @angular/http: 2.4.7
  • @angular/platform-browser: 2.4.7
  • @angular/platform-browser-dynamic: 2.4.7
  • @angular/router: 3.4.7
  • @angular/cli: 1.0.0-beta.32.3
  • @angular/compiler-cli: 2.4.7
  • @ngrx/[email protected]
  • @ngrx/[email protected]
  • @ngrx/[email protected]
  • rxjs: 5.1.1
like image 229
Carlos Mermingas Avatar asked Nov 19 '22 01:11

Carlos Mermingas


1 Answers

To answer your concluding questions:

  • Am I doing something wrong?
  • No, I don't reckon you are doing anything wrong.
  • Is it incorrect to expect that actions are processed by the reducers in the same order that they are dispatched?
  • That order would seem logical but apparently you can't expect that at the moment

There seems to be a bug causing this behaviour. You are most probably experiencing it since you are directly mapping to another action. Usually, if you have an asynchronous operation or something like that, the reducer has time to finish before the effect listening to the next action starts.

Perhaps not a part of your question, but a solution to your specified problem would be to navigate to your new route directly in SUCCESS with the help of your payload, or pass the payload to ADVANCE.

Links below are reported issues in effects-, store- and rxjs-projects that are related to yours:

  • https://github.com/ngrx/effects/issues/58
  • https://github.com/ngrx/store/issues/279
  • /ReactiveX/rxjs/issues/2155 (too little reputation to link to this one as well)

Seems like they're working on it :)

like image 75
Peter Wenström Avatar answered May 13 '23 11:05

Peter Wenström