Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐞[BUG]: Dispatch action handler returns after changing the state #1545

Closed
omirobarcelo opened this issue Feb 21, 2020 · 5 comments
Closed
Labels
domain: core investigate Requires some investigation

Comments

@omirobarcelo
Copy link

Affected Package

The issue is caused by package @ngxs/store, the Actions class.

Description

According to the docs (https://www.ngxs.io/advanced/action-handlers):

The action handler is an Observable that receives all the actions dispatched before the state takes any action on it.

But the actions with status DISPATCHED are emitted after the state has already changed.

🔬 Minimal Reproduction

https://stackblitz.com/edit/ngxs-simple-demo-fm31wo

I imagined that the state in state on dispatched action would show the state before the action is applied.

Environment


Libs:
- @angular/core version: 8.2.14
- @ngxs/store version: 3.6.2

Browser:
- [X] Chrome (desktop) version 80.0.3987.106
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
 
For Tooling issues:
- Node version: 12.13.0
- Platform:  Windows 10
@markwhitfeld
Copy link
Member

Thank you for reporting this.
Out of interest, what is your use case where the order of these matters?

@omirobarcelo
Copy link
Author

@markwhitfeld I'm trying to implement an undo function. I wanted to save the state before applying the action (since I haven't received an answer on saving just the changes ngxs-labs/immer-adapter#373).

Right now I opted to use a plugin, but using the action handler would be much better.

@ahnpnl
Copy link

ahnpnl commented Feb 23, 2020

I also observed similar thing when using ofActionDispatched operator. I was wondering if that is design intended but imo, when action is dispatched, the state shouldn’t change til action is successful.

@Krismix1
Copy link

I have found myself also needing order-dependant logic. My use case goes as follows:
I need to observe the changes of state until a certain action is triggered. The problem is that even with ofActionDispatched, the action is only caught after the state was modified. Thus, the final observable emits more values than desired.

Simplified version of my logic:

function build() {
    return combineLatest([this.subject$, this.stateObs$]).pipe(
      takeUntil(this.actionStream$.pipe(ofActionDispatched(MyAction))),
      map(
        ([val1, val2]) => val1 && val2 ),
    );
}

In my case, adding a delay and moving operators around like pipe(map(...), delay(100), takeUntil(...)) fixes the issue, but this is just a workaround.

The actual behaviour contradicts with the order of events described in the Action Life-cycle docs
https://www.ngxs.io/advanced/actions-life-cycle

@arturovt arturovt added domain: core investigate Requires some investigation labels Dec 17, 2022
@arturovt
Copy link
Member

This is by design. There's no way to make the Actions stream emit the DISPATCHED value before the state is updated. NGXS internally subscribes to the Actions stream too, and filters DISPATCHED actions to invoke their handlers and update the state. When you subscribe to the Actions stream, the second subscriber is called synchronously after the state has been updated since it's been updated by the first subscriber, which is NGXS.

We would need to re-order observers in the matter they're subscribing to the Actions stream, which doesn't overcome the ROI of this software decision.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
domain: core investigate Requires some investigation
Projects
None yet
Development

No branches or pull requests

5 participants