Angular 角度循环依赖。服务->;国家->;服务如何应对?

Angular 角度循环依赖。服务->;国家->;服务如何应对?,angular,ionic-framework,architecture,rxjs,ngxs,Angular,Ionic Framework,Architecture,Rxjs,Ngxs,更新:(更新位于顶部) 在使用NGXS时,我使用下一种方法重新构建了我的服务/状态: 在类中,调用该服务的对象-不再调用该服务。相反,它发出了一个动作。因此,状态为该操作启动适当的reducer,并调用服务方法renewAccessToken,将refreshttoken作为参数填充。 这是我的好方法 但是。。。我还有一个问题(完全是另一个问题)。 分派操作的类实际上是一个自定义HTTP_拦截器,如果令牌刷新成功,我想发出一个request.clone() 我正在考虑决议。。。欢迎提出建议 初始

更新:(更新位于顶部)

在使用NGXS时,我使用下一种方法重新构建了我的服务/状态: 在类中,调用该服务的对象-不再调用该服务。相反,它发出了一个动作。因此,状态为该操作启动适当的reducer,并调用服务方法renewAccessToken,将refreshttoken作为参数填充。 这是我的好方法

但是。。。我还有一个问题(完全是另一个问题)。 分派操作的类实际上是一个自定义HTTP_拦截器,如果令牌刷新成功,我想发出一个request.clone()

我正在考虑决议。。。欢迎提出建议

初始问题:

[ng] WARNING in Circular dependency detected:
[ng] src/app/services/auth.service.ts -> src/app/store/auth/state.ts -> src/app/services/auth.service.ts
我理解这个错误。 但我来这里是想征求你的意见,如何应对。 我应该如何使用最佳实践来改变我的结构

我用的是离子+角度+NGX

我目前的想法是直接从
localStorage
获取刷新令牌,而不在
AuthService
中注入
AuthState
。但我认为这并不是解决这些问题的最佳办法

我的当前代码附在下面:

状态

import { State, Action, StateContext, Selector, Store } from '@ngxs/store';
import { tap, catchError } from 'rxjs/operators';
import { ImmutableContext } from '@ngxs-labs/immer-adapter';
import { AuthModel } from './model';
import { of } from 'rxjs';
import { JwtHelperService } from '@auth0/angular-jwt';
import { AuthService } from 'src/app/services/auth.service';
import {
  TryLogin,
  LoginFailed,
  LoginSucceess,
  TryLogout,
  LogoutSuccess
} from 'src/app/pages/login/store/actions';
import { Injectable } from '@angular/core';
import { UiService } from 'src/app/services/ui.service';
import { Unauthorized } from 'src/app/errors/response-errors/unauthorized';

@State<AuthModel>({
  name: 'auth',
  defaults: {
    token: null,
    refreshToken: null
  }
})
@Injectable()
export class AuthState {
  @Selector()
  static token(state: AuthModel): string | null {
    return state.token;
  }

  @Selector()
  static refreshToken(state: AuthModel): string | null {
    return state.refreshToken;
  }

  @Selector()
  static isAuthenticated(state: AuthModel): boolean {
    if (state.token) {
      const jwtHelper = new JwtHelperService();

      if (!jwtHelper.isTokenExpired(state.token)) {
        return true;
      }
    }
    return false;
  }

  constructor(
    private authService: AuthService,
    private store: Store,
    private uiService: UiService
  ) {}

  @Action(TryLogin)
  @ImmutableContext()
  login({ setState }: StateContext<AuthModel>, { payload }: TryLogin) {
    this.uiService.displayLoading();
    return this.authService.login(payload).pipe(
      catchError(err => {
        this.uiService.dismissLoading();
        if (err instanceof Unauthorized) {
          this.store.dispatch(new LoginFailed());
        }
        return of(null);
      }),
      tap((result: any) => {
        this.uiService.dismissLoading();
        if (result) {
          setState((state: AuthModel) => {
            state.token = result.token;
            state.refreshToken = result.refresh_token;

            return state;
          });
          this.store.dispatch(new LoginSucceess());
        }
      })
    );
  }

  @Action(TryLogout)
  @ImmutableContext()
  logout({ setState }: StateContext<AuthModel>, {}: TryLogout) {
    setState((state: AuthModel) => {
      state.token = null;
      state.refreshToken = null;

      return state;
    });
    this.store.dispatch(new LogoutSuccess());
  }
}
import { Injectable } from '@angular/core';
import { ApiService } from './api.service';
import { HttpClient } from '@angular/common/http';
import { LoginForm } from '../pages/login/interfaces/login-form';
import { AuthState } from '../store/auth/state';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AuthService extends ApiService {
  refreshToken$: Observable<string>;

  constructor(http: HttpClient) {
    super(http);
  }

  login(credentials: LoginForm) {
    console.log('AuthService:login');
    return this.post('/login', {
      email: credentials.username,
      password: credentials.password
    });
  }

  renewAccessToken(): Observable<any> {
    console.log('AuthService:renewAccessToken');
    return this.post('/renew-access-token', {
      refresh_token: AuthState.refreshToken
    });
  }
}

只需移动刷新令牌和存储在服务中的令牌,这就更有意义了。您是否使用过NGXS?是的,我在项目中使用它,但我也使用单例服务来存储临时数据。我不在staterefreshToken中创建实例属性,因为它不是临时数据。它在身份验证状态下存在很长一段时间,这会将其保存在数据库下的localStorage中。如果确实要保存在状态中,为什么不在状态中创建另一个操作以保存令牌,并且当身份验证服务获取令牌时,可以在状态操作函数中调度该操作,那么您应该能够避免循环依赖。只需将刷新令牌和令牌移动到服务中存储,这更有意义。您是否使用过NGXS?是的,我在项目中使用它,但我也使用单例服务存储临时数据。我不在staterefreshToken中创建实例属性,因为它不是临时数据。它在身份验证状态下存在很长一段时间,这会将其保存在数据库下的localStorage中。如果您真的想保存在状态中,为什么不在状态中创建另一个操作来保存令牌?当身份验证服务获取令牌时,您可以在状态操作函数中调度该操作,那么您应该能够避免循环依赖。