Angular认证Signal登录后状态不更新,登出正常问题求助
问题:登录后状态不更新,需刷新页面才生效
问题场景与代码
我有一个展示登录状态的组件,相关代码如下:
组件模板代码
{{loggedIn()}}
组件TS代码
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, WritableSignal } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatToolbarModule } from '@angular/material/toolbar'; import { MatIconModule } from '@angular/material/icon'; import { RouterOutlet } from '@angular/router'; import { CompanyLoginComponent } from './company-login/company-login.component'; import { AuthService } from './auth.service'; import { AsyncPipe } from '@angular/common'; import { MatSidenavModule } from '@angular/material/sidenav'; @Component({ selector: 'app-company-facing', standalone: true, imports: [ MatToolbarModule, MatButtonModule, MatIconModule, RouterOutlet, CompanyLoginComponent, AsyncPipe, MatSidenavModule, ], templateUrl: './company-facing.component.html', styleUrl: './company-facing.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, providers: [AuthService,] }) export class CompanyFacingComponent { constructor(private auth: AuthService, private cdr: ChangeDetectorRef) {} get loggedIn() { return this.auth.loggedIn; } async logout() { await this.auth.logout(); } forceChangeDetection() { this.cdr.detectChanges(); } }
AuthService代码
import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { firstValueFrom } from 'rxjs'; import { signal, WritableSignal } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class AuthService { loggedIn: WritableSignal<boolean> = signal(false); constructor(private http: HttpClient) { this.loggedIn.set(!!localStorage.getItem('accessToken')); } async login(email: string, password: string) { let res = await firstValueFrom( this.http.post<{ access_token: string }>('https://api.self-serve.just-solve.com/api/login', { email, password }) ); console.log(res); if (res.access_token) { this.loggedIn.set(true); console.log("logged in updated to true!"); } console.log(this.loggedIn()); localStorage.setItem('accessToken', res.access_token); return res; } async logout() { try { let res = await firstValueFrom( this.http.post('https://api.self-serve.just-solve.com/api/logout', {}) ); this.loggedIn.set(false); } catch (e) { console.error(e); } localStorage.removeItem('accessToken'); } }
当前问题
登出时登录状态能正确切换为false,但登录后状态仍保持false,必须刷新页面才能更新。
原因分析
核心问题是服务实例不统一:
- AuthService本身配置了
providedIn: 'root',属于根注入的单例服务; - 但
CompanyFacingComponent的元数据里又在providers数组中声明了AuthService,这会导致组件自己创建一个局部的AuthService实例,和CompanyLoginComponent(以及其他组件)注入的根实例不是同一个对象; - 登录时,
CompanyLoginComponent调用的是根实例的login方法,更新的是根实例的loggedIn信号,但CompanyFacingComponent绑定的是自己局部实例的loggedIn信号,所以状态不会同步; - 登出时,是
CompanyFacingComponent自己调用局部实例的logout方法,更新的是局部实例的信号,所以看起来状态生效了。
解决方案
直接移除CompanyFacingComponent的providers数组中的AuthService,让组件使用根注入的单例AuthService:
修改后的组件元数据部分:
@Component({ selector: 'app-company-facing', standalone: true, imports: [ MatToolbarModule, MatButtonModule, MatIconModule, RouterOutlet, CompanyLoginComponent, AsyncPipe, MatSidenavModule, ], templateUrl: './company-facing.component.html', styleUrl: './company-facing.component.scss', changeDetection: ChangeDetectionStrategy.OnPush // 移除了 providers: [AuthService,] 这一行 })
这样调整后,所有组件共享同一个AuthService实例,登录时更新loggedIn信号后,Angular的OnPush变更检测会自动响应信号的变化,模板中的{{loggedIn()}}会实时更新登录状态,无需手动调用forceChangeDetection方法。
内容的提问来源于stack exchange,提问作者Francesco Manicardi
相关产品推荐
相关产品推荐

