如何在NgRx中等待效果完成。我陷入了这种境地。我有一个效果,从存储中加载一个令牌,并根据是否找到令牌来调度更新存储的操作。
autoLogin$ = createEffect(() => this.actions$.pipe(
ofType(AuthActions.startAutoLogin),
switchMap(action => {
return from(AuthUtils.getTokenFromStorage(USER_TOKEN_STORAGE_KEY));
}),
switchMap(token => {
if (AuthUtils.isProvidedTokenNotExpired(token)) {
return from(AuthUtils.getTokenData(token));
}
return EMPTY;
}),
map(tokenData => {
if (tokenData) {
return AuthActions.autoLogin({payload: tokenData});
}
})
));
动作AuthActions.autoLogin({payload: tokenData})
被调度并用于更新存储中的一个字段:
export interface AuthState {
isLoggedIn: boolean,
}
最后,我在Router Guard中使用该字段来检查用户是否登录:
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanLoad, CanActivate {
constructor(private router: Router,
private store: Store<fromAuth.AuthState>) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return this.store.select(AuthSelectors.selectIsLoggedIn).pipe(
tap(isLoggedId => {
if (!isLoggedId) {
this.router.navigateByUrl('/login').then();
}
}),
);
}
}
问题是:
Router Guard在生效之前执行,Store更新太迟,用户被重定向到登录页面。当我查看重定向后存储的状态时,isLoggedIn
就是true
。
是否可以在Router Guard中等待效果执行重定向结束?
我也有同样的行为,并设法修复了它。
我所做的是将isLoginResolved添加到状态中。成功或失败登录/自动登录后,我将属性设置为true,因为登录/自动登陆发生了。
在警卫中,我正在做自动登录的部分。发生的事情是,我正在检查用户是否没有登录或没有登录/自动登录尝试,然后它会尝试自动登录用户;在最后一部分中,我正在等待isLoginResolved为true。
user.state.ts
export interface UserState { isLoginResolved: boolean; userDetails: Player | null; token: string; authError: any; }
auth.guard.ts
canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): boolean | Observable<boolean> | Promise<boolean> { return this.authService.getIsAuth().pipe( tap((isAuthenticated: boolean) => { if (!isAuthenticated) { this.router.navigate(["../"]).then(); } }) ); }
身份验证服务.ts
getIsAuth() { const isAuthenticated$: Observable<boolean> = this.store.select(isAuthenticated); const isLoginResolved$: Observable<boolean> = this.store.select(selectUserResolved); zip(isLoginResolved$, isAuthenticated$) .pipe(map(([isLoginResolved, isAuthenticated]) => ({ >isLoginResolved, isAuthenticated }))) .pipe(first()) .subscribe((x) => { if (!x.isAuthenticated || !x.isLoginResolved) { this.store.dispatch(autoLogin()); } }); return this.store .select(selectUserResolved) .pipe(filter((resolved) => resolved)) .pipe(map(() => isAuthenticated$)) }