Reputation: 2158
store.select()
emits previous store state.
Is it possible to subscribe to changes from "this point forward" without getting the previous store value?
Upvotes: 13
Views: 8795
Reputation: 3104
Just sharing my thoughts (and solution) after reading @Niz's answer.
This is a perfect, practical example of how to utilize the difference between null
and undefined
. When you initialize your state with null, you're basically saying:
I don't care about differentiating the nullable future state from the initial one. I don't care if the user is null because he has signed out or because he just didn't sign in
However, in some cases this could be insufficient. Think about a case when you need an asynchronous call (implemented in effects
) in order to know if you have an active user session. Based on the select
ion result, you should determine whether to show a login modal or redirect to a content page. With initial user state set to null, you'd pop up that modal and then immediately hide it when that asynchronous call returns a session value.
With initial state set to undefined
you can make that differentiation, saying:
Initially, I know nothing about my state, then it's
undefined
. When I know it should be empty, then I'll set it tonull
.
Therefor, as a practical solution, I set everything on the app's initialState
to undefined
. In the example above, I need to know if the login modal should be displayed after the asynchronous call resolves. skipWhile(val => val === undefined)
will do the job for sure, but repeating it over and over again feels a little tedious. Plus, it's not really descriptive to our use case. I created a rxjs-custom-operators.ts
with a shortened implementation:
import { Observable } from "rxjs";
import { skipWhile } from "rxjs/operators";
export const skipInitial = () => {
return <T>(source: Observable <T>): Observable<T> => {
return source.pipe(skipWhile(value => value === undefined));
};
};
Usage:
navigateOnLoad(): void {
this.store.pipe(select(selectAuthUser), skipInitial()).subscribe((authUser: CognitoUser) => {
// Navigate to login if !authUser, else navigate to content...
});
}
Upvotes: 3
Reputation: 506
skip operators need piping now, you can use skip like this:
store.pipe(select(...), skip(1));
In terms of the 'hacky' part, it is a standard practice in ngrx to set an initial state with properties set to null. and that value gets emitted initially. so the first value you get will be null in these cases.
Alternatively you could also consider skipwhile(https://www.learnrxjs.io/learn-rxjs/operators/filtering/skipwhile) and use it like this:
store.pipe(select(...), skipWhile(val => val === undefined));
where undefined is the initial value of the property you are interested in. Rather than setting the initial value of the property to undefined, you could use null as the initial value as well, and change the above skipwhile() accordingly.
Upvotes: 7