I try to synchronize initialization of app and initialization of ngrx store. It's important because app uses the refresh token mechanism to auto-login. Race produces many problems like cannot read property of undefined
.
Method below is used in APP_INITIALIZER
token.
// import { ActionsSubject, ScannedActionsSubject } from '@ngrx/store';
public async load(): Promise<any> {
return this.refreshToken().pipe(
tap(res => {
this.subject.next(authActions.refreshTokenOnInitSuccess({token: res.token}));
}),
catchError((error: HttpErrorResponse) => {
// SOME CODE
}),
takeUntil(this.actions$.pipe(ofType(authActions.initSuccess))) // HERE, init not stop, work like without this line
).toPromise().catch(error => {
console.error('Error when refreshing JWT access token on startup', error);
});
}
private refreshToken(): Observable<JwtTokenResponse> {
return this.httpClient.post<JwtTokenResponse>(`${AUTH_URL}/refresh`, {});
}
I tried to use exhaustMap
instead of takeUntil
but initialization never ended. I know it can be fixed by Promise
with resolve
like:
return new Promise((resolve, reject) => {
this.refreshToken().pipe(
tap(res => {
this.subject.next(authActions.refreshTokenOnInitSuccess({ token: res.token }));
}),
catchError((error: HttpErrorResponse) => {
// SOME CODE
reject(error);
return throwError(error);
}),
).subscribe();
this.actions$.pipe(ofType(authActions.initSuccess)).subscribe(resolve);
}).catch(error => {
console.error('Error when refreshing JWT access token on startup', error);
});
but I try to find rxjs
way to pause initialization of app until store set state.
You have to subscribe to your init success action before you trigger this action. You can use forkJoin
to combine your action and your refresh/trigger stream. (combineLatest
or zip
should also work)
public async load(): Promise<any> {
const refresh = this.refreshToken().pipe(
tap(res => {
this.subject.next(authActions.refreshTokenOnInitSuccess({token: res.token}));
}),
catchError((error: HttpErrorResponse) => {
// SOME CODE
}),
);
return forkJoin(
// add your action stream first, use take(1) to complete the stream
this.actions$.pipe(ofType(authActions.initSuccess), take(1)),
refresh
).toPromise().catch(error => {
console.error('Error when refreshing JWT access token on startup', error);
});
}