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

时间:2019-07-10 06:35:31

标签: angular typescript redux ngrx

故事:

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

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

问题:

何时执行调度动作。即使在 @Effect()中设置 {dispatch:false} ,“ LoginSuccess”操作也始终执行无限循环。经过尝试,并通过谷歌解决方案搜索。这个问题总是在我的项目中。 希望有一些关于stackoverflow的朋友能给我一些帮助。〜谢谢。

部分代码:

  

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
    };
  }),
....
...
  

effect.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-routing.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' }
];
....

环境:

Angular Cli:8.0.3

NgRx存储/效果:8.0.1

操作系统:Ubuntu 18.04

..谢谢

1 个答案:

答案 0 :(得分:0)

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

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});