简体   繁体   English

BehaviorSubject不会立即更改值

[英]BehaviorSubject doesn't immediately change value

I am creating a custom login service with AuthGuard from Angular . 我正在使用Angular AuthGuard创建自定义登录服务。 I have a SessionService which have methods such a login() or onUserLoggedIn() which basically returns BehaviorSubject with the current value of user status (logged in/not logged in). 我有一个SessionService ,其中具有诸如login()onUserLoggedIn()类的方法,这些方法基本上返回具有用户状态(登录/未登录)的当前值的BehaviorSubject Based on this service I created an implementation of AuthGuard implements CanActivate service. 基于此服务,我创建了一个AuthGuard implements CanActivate服务的AuthGuard implements CanActivate I call onUserLoggedIn method and check the current value in subject. 我调用onUserLoggedIn方法并检查subject中的当前值。 The problem here is that in login method value is changed after the AuthGuard call onUserLoggedIn . 这里的问题是在AuthGuard调用onUserLoggedIn之后, login方法中的值已更改。 Therefore in a first attempt I receive false value from BehaviorSubject but when I try the second time, I received a true value. 因此,在第一次尝试中,我从BehaviorSubject收到了错误的值,但是当我第二次尝试时,我收到了一个真值。

How can I change the implementation of those two services to achieve current value in a first attempt? 第一次尝试如何更改这两项服务的实现以实现当前价值?

AuthGuard: AuthGuard:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
    : Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

    console.log('auth');

    return this.sessionService.onUserLoggedIn()
      .pipe(
        map(res => {
          console.log('res', res);
          return res;
        }),
        take(1),
        tap(allowed => {
          console.log(allowed);
          if (!allowed) {
            this.router.navigate(['/login']);
          }
        })
      );
  }

SessionService: SessionService:

private isLoggedIn = new BehaviorSubject(false);

  constructor(private apiService: ApiService) {
  }

  login(user: User): Observable<any> {
    console.log('hello before');
    return this.apiService.post(`${BASE_URL}/login`, user)
      .pipe(
        tap((token: Token) => {
          this.isLoggedIn.next(true);
          localStorage.setItem('token', token.token);
          console.log('hello');
        })
      );
  }

  onUserLoggedIn() {
    return this.isLoggedIn;
  }

First attempt goes with printing value: 第一次尝试具有打印价值:

  • SessionService.ts:19 hello before SessionService.ts:19之前您好
  • AuthGuard.ts:17 auth AuthGuard.ts:17身份验证
  • AuthGuard.ts:22 res false AuthGuard.ts:22 res假
  • AuthGuard.ts:27 false AuthGuard.ts:27错误
  • SessionService.ts:25 hello SessionService.ts:25您好

The second one (which I expect to be first): 第二个(我希望是第一个):

  • SessionService.ts:19 hello before SessionService.ts:19之前您好
  • AuthGuard.ts:17 auth AuthGuard.ts:17身份验证
  • AuthGuard.ts:22 res true AuthGuard.ts:22 res是
  • AuthGuard.ts:27 true AuthGuard.ts:27是
  • SessionService.ts:25 hello SessionService.ts:25您好

The nature of BehaviorSubject is, it emit the given value immediately whenever you subscribe. BehaviorSubject的本质是,只要您订阅,它就会立即发出给定值。

So based on your use case use Subject. 因此,根据您的用例使用Subject。 Also use skip operator to skip the first value. 也可以使用跳过运算符跳过第一个值。

return this.sessionService.onUserLoggedIn()
      .pipe(
        take(1),
        map(res => {
          console.log('res', res);
          return res;
        }),
        tap(allowed => {
          console.log(allowed);
          if (!allowed) {
            this.router.navigate(['/login']);
          }
        })
      );
  }

use startsWith(false) in other components. 在其他组件中使用startsWith(false)

Can you try returning it asObservable? 您可以尝试将其返回为可观察到吗?

onUserLoggedIn() {
        return this.isLoggedIn.asObservable();
      }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM