首页 > 解决方案 > Angular 路由器保护中的 NgRx 调用调度操作将执行无限循环

问题描述

故事:

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

我的理想是调用一个rest api来验证本地存储令牌内容。当rest api结果为“success”时,返回(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);
        }
      })
    );
...
...

动作.ts:

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

减速器.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-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 { }
....

应用程序路由.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

操作系统:Ubuntu 18.04

..谢谢

标签: angulartypescriptreduxngrx

解决方案


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

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

推荐阅读