NgRx如何等待效果执行结束



如何在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$))
}    

最新更新