store.dispatch(...).subscribe(...) called twice for async Actions

Created on 20 Mar 2018  ·  10Comments  ·  Source: ngxs/store

store.dispatch(...).subscribe(...) called twice when Action with async method implementation dispatched.
This is leading bugs as we have some business logic executed twice with in subscribe method.

if you remove async , this will print once as expected.

This issue got introduced in 2.0 release. it was working fine in 1.x

stackblitz:
https://stackblitz.com/edit/ngxs-router-sumo

import { State, Action, StateContext } from 'ngxs';

export class Add {}

@State({
  name:'app',
  defaults: {
    count: 0
  }
})
export class AppState {
  @Action(Add)
  async add({ getState, setState }: StateContext<any>) {
    await new Promise(resolve => setTimeout(resolve, 1000));
    console.log("in add")
    setState({
      count: getState().count + 1
    })
  }
}
  onClick() {
    this.store.dispatch(new Add()).subscribe( () => {
      console.log('... this will print twice')
    });
  }

Most helpful comment

Hi @yarrgh
Having same issue. If I'm subscribing to observable from Store.dispatch() I see my action twice in a log:
2018-05-22_01-09-57

However console.log(); inside action prints in console only once.

All 10 comments

@xmlking can you confirm this only happens twice this way? it doesn't happen when not using way or when using an observable?

It happened when “async” is used. If I remove async it worked normally. I haven’t tested observable yet. Will do ...

It happens with an observable as well. Even in the dev tools I see double entries (sometimes triple) entries for my async actions. I'm also seeing "Object" entries. No idea what they are why they are there. On top of this, the entries in the dev tools are out of order. The action being dispatched comes after a dispatched action inside another.

Example: I subscribe a dispatched CreateRecipe action inside my component (only dispatched once). The action then sets initial state (pending: true) and then calls the backend via observable form the RecipeService. It then dispatches a CreateRecipeSuccess with the created object to set the state otherwise it dispatches CreateRecipeFail. In the dev tools, CreateRecipeSuccess shows up first, followed by two entries of "Object" and then 3 entries of CreateRecipe.

image

I believe one of the entries for CreateRecipe is me subscribing to the dispatched action. If I remove the subscription, only two entries for CreateRecipe are in the dev tools.

ok I can reproduce in the example and in a test, if you return a promise it happens. @amcdnl any ideas? Is it trying to dispatch a new action?

@jschwarty ^

I think it’s because the observable you are creating in store.dispatch is unicast. So each subscribe gets its own execution context. Maybe that needs to be a multicast (like a Subject or BehaviorSubject)

I believe this fixes it - https://github.com/amcdnl/ngxs/commit/ce4e6638fb2d88dffdf49c5bc063c72109f097bf

@jschwarty - can u sanity check this for me?

That mostly fixed it. However, this doesn't fix subscribing to the observable returned from Store.dispatch(). If you subscribe to that observable, it causes the action to be dispatched again.

I guess this may be a different issue. I'll open up a new issue.

Hi @yarrgh
Having same issue. If I'm subscribing to observable from Store.dispatch() I see my action twice in a log:
2018-05-22_01-09-57

However console.log(); inside action prints in console only once.

Was this page helpful?
0 / 5 - 0 ratings