Angular中如何让按钮等待身份认证状态校验完成后再渲染显示
问题根因
- 你当前只订阅了
authChanged事件,该事件仅在登录/登出操作主动调用sendAuthStateChangeNotification时才会触发推送,组件初始化时没有主动拉取当前最新的认证状态,导致初始值永远是你声明时写的false - 使用普通
Subject作为事件源,它不会向新订阅者推送之前已经发出过的状态,如果登录操作发生在当前组件初始化之前,组件会错过之前的状态通知,永远拿不到正确的认证值
方案1:最小改动修复(快速生效)
直接在组件ngOnInit订阅逻辑后,主动拉取一次当前认证状态,同时补充订阅销毁逻辑避免内存泄漏:
export class RecipeDetailsComponent implements OnInit, OnDestroy { public isUserAuthenticated: boolean = false; private authSub?: Subscription; ngOnInit(): void { this.authSub = this.userService.authChanged .subscribe(res => { this.isUserAuthenticated = res; }) // 新增:主动获取当前最新的认证状态 this.isUserAuthenticated = this.userService.isUserAuthenticated(); } // 新增:组件销毁时取消订阅避免内存泄漏 ngOnDestroy(): void { this.authSub?.unsubscribe(); } }
方案2:优化Service实现(从根源避免漏通知)
把Service里的普通Subject替换为BehaviorSubject,初始化时就传入当前的认证状态,新订阅的组件会自动收到最近一次的认证状态,不需要再手动拉取:
export class UserService { // 替换为BehaviorSubject,初始值直接取当前认证状态 private _authChangeSub = new BehaviorSubject<boolean>(this.isUserAuthenticated()); public authChanged = this._authChangeSub.asObservable(); public sendAuthStateChangeNotification = (isAuthenticated: boolean) => { this._authChangeSub.next(isAuthenticated); } public isUserAuthenticated = (): boolean => { const token = localStorage.getItem("token"); return token != null && !this._jwtHelper.isTokenExpired(token); } }
改完之后组件只需要正常订阅即可,不需要额外手动拉取状态,就算页面刷新、组件晚加载也不会错过认证状态。
方案3:用Angular async管道进一步简化(推荐)
不需要手动管理订阅和销毁,直接在模板里绑定Observable:
组件ts代码:
export class RecipeDetailsComponent { // 直接把authChanged Observable暴露给模板 public isUserAuthenticated$ = this.userService.authChanged; constructor(private userService: UserService) {} }
模板代码修改*ngIf逻辑:
<button type="button" *ngIf="isUserAuthenticated$ | async" class="btn btn-primary float-right m-2" data-bs-toggle="modal" data-bs-target="#exampleModal" (click)="addClick()" data-backdrop="static" data-keyboard="false"> Add Coffee </button>
该方案由Angular自动管理订阅的声明周期,不需要手动处理销毁逻辑,也不会出现状态更新不及时的问题。
内容的提问来源于stack exchange,提问作者Rogal
相关产品推荐
相关产品推荐

