Reputation: 657
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.
Upvotes: 0
Views: 888
Reputation: 14129
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);
});
}
Upvotes: 1
Reputation: 1863
When I run into such things I wrap my observables/subscription in a Promise:
const result = await new Promise<string>(resolve => {
this.service.subscribe(res => {
resolve(res);
});
});
Should work for your case if implemented correctly.
Upvotes: 0