@ngrx selector emitting twice in parallel

Viewed 1774

I have a quite simple selector

export const isLoading = createSelector(
  state => state.$loading
);

and two actions StartLayoutNavigationAction and EndLayoutNavigationAction that just set the $loading flag accordingly. I invoke these functions once, my actions get logged:

ACTION – [Layout] Start navigation StartLayoutNavigationAction {layout: "login", type: "[Layout] Start navigation"}
ACTION – [Layout] End navigation EndLayoutNavigationAction {type: "[Layout] End navigation"}

So one would assume that the selector would emit once when the first action was invoked, and once when the second one was invoked. No actions in between.

BUT:

The selector seems to emit twice in parallel. I piped as following:

layoutLoading$: Observable<boolean> = this.store.pipe(
  select(isLoading),
  distinctUntilChanged((x, y) => {
    console.log("Comparison:", x, y);
    return x === y;
  }),
  tap(value => console.log("New val:", value))
);

And this is the output:

ACTION – [Layout] Start navigation StartLayoutNavigationAction {layout: "login", type: "[Layout] Start navigation"}
Comparison:  false true
New val: true
Comparison: false true
New val: true
ACTION – [Layout] End navigation EndLayoutNavigationAction {type: "[Layout] End navigation"}
Comparison: true false
New val: false
Comparison: true false
New val: false

Am I getting something wrong? Is this expected behaviour?

2 Answers

Based on comments

Are you sure that layoutLoading$ have exactly one subscription? For example you have multiple async pipe, multiple component instance. - @Buggy

const source$ = of(1).pipe(
  tap(value => console.log("New val:", value))
);

source$.subscribe();
source$.subscribe();
// 1
// 1

Ok you're right, I have two subscriptions with async. I didn't know that this works per subscription. So when I want to react to distinct changes (in addition to the async pipes), I will need a second observable pipe, right? - @Giacomo Voß

Yes, if i understood correctly:

source$
  .pipe(distinctUntilChanged(fn))
  .subscribe(/* do something */)

Every time the state changes your selector will execute. This is because it's parameter is the whole state.

Related