Angular 路由器防护中的 NgRx 呼叫调度操作将执行无限循环



>故事:

大家好。我是使用NgRx库的新手。在我的角度项目中,我使用路由器防护来防止未经身份验证的用户访问未经身份验证的网站。

我的理想是调用 rest api 来验证本地存储令牌内容。当 rest api 结果为 "success" 时,返回 of(true) 之前,执行"store.dispatch(LoginSuccess)">以更新 Store 中的登录身份验证信息。

问题:

何时执行调度操作。"LoginSuccess"操作始终执行无限循环,即使在@Effect()中设置{调度:false}。尝试并通过谷歌解决方案搜索它之后。这个问题总是在我的项目中。 希望栈溢出上的一些朋友能给我一些帮助~谢谢。

部分代码:

auth.guard.ts

.....
....
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
const authData: {email: string, token: string} = JSON.parse(
String(localStorage.getItem('User')));
const authToken = authData && authData.token;
// loginServ is a REST API for verify token
return this.loginServ.VerifyToken(authToken).pipe(
concatMap((res: AuthResult) => {
if (res.result === 'success') {
this.store.dispatch(LoginSuccess({
isAuthenticated: true,
email: authData && authData.email,
token: authToken,
result: 'success',
message: 'success'
}));  // <-- execute action infinite.
return of(true);
} else {
this.store.dispatch(LoginFailed({
isAuthenticated: false,
email: authData && authData.email,
token: authToken,
result: 'failed',
message: 'token illegal'
}));
localStorage.removeItem('User');
this.router.navigate(['']);
return of(false);
}
})
);
...
...

Action.ts:

...
export const LoginSuccess = createAction(
'[auth] Login Success',
props<{
isAuthenticated: boolean,
email: string,
token: string,
result: string,
message: string,
}>()
);
....
...

reducer.ts

....
....
export const loginReducer = createReducer(
defaultState,
on(Login),
on(LoginSuccess, (state, userInfo) => {
console.log(state);     // <-- for debug.
console.log(userInfo);  // <-- for debug.
return {
...state,
...userInfo
};
}),
on(LoginFailed, (state, result) => {
return {
...state,
...result
};
}),
....
...

效果.ts

....
...
loginSuccess = createEffect(() => this.actions$
.pipe(
ofType(LoginSuccess),
map((user: any) => {
console.log(user);
const beStoreInfo = {
email: user.email,
token: user.token,
};
localStorage.setItem(
'User',
JSON.stringify(beStoreInfo));
return {
type: '[auth] Login Success',
isAuthenticated: true,
email: user.email,
token: user.token,
result: user.result,
message: user.message
};
}),
), {dispatch: false});
....
...

service_overview-routeting.module.ts

....
// using lazy loading module
const routes: Routes = [
{
path: '',
canActivate: [AuthGuard],
component: ServiceOverviewComponent},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ServiceOverviewRoutingModule { }
....

app-routing.module.ts

使用延迟加载模块。

....
...
const routes: Routes = [
{ path: 'login', loadChildren: () => import('./login/login.module')
.then(m => m.LoginModule)},
{ path: 'register', loadChildren: () => import('./register/register.module')
.then(m => m.RegisterModule)},
{ path: 'service_overview', loadChildren: () => import('./service-overview/service-overview.module')
.then(m => m.ServiceOverviewModule)},
{ path: '', redirectTo: 'login', pathMatch: 'full' }
];
....

环境:

角度 Cli:8.0.3

NgRx 存储/效果:8.0.1

操作系统: 乌班图 18.04

..谢谢

您的登录成功效果将返回另一个登录成功操作,从而导致无限循环。

loginSuccess = createEffect(() => this.actions$
.pipe(
ofType(LoginSuccess),
map((user: any) => {
console.log(user);
const beStoreInfo = {
email: user.email,
token: user.token,
};
localStorage.setItem(
'User',
JSON.stringify(beStoreInfo));
// remove this ⬇
return {
type: '[auth] Login Success',
isAuthenticated: true,
email: user.email,
token: user.token,
result: user.result,
message: user.message
};
// end remove this ⬆
}),
), {dispatch: false});

最新更新