如何在现有Angular认证服务中应用Angular Signals?
在Angular认证服务中引入Signals的分步改造
下面是针对你的认证服务,逐步引入Angular Signals的具体改动,从微小调整到状态管理优化:
1. 将Firebase Auth状态Observable转为Signal
原代码中authState$是Observable,我们可以用toSignal把它转换为Signal,让组件无需手动处理订阅/取消订阅,更简洁地获取状态。
代码修改:
import { Injectable, inject, signal, effect } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; // ...保留其他原有导入 @Injectable({ providedIn: 'root' }) export class AuthService { private angularAuth = inject(Auth); // 将Observable转为Signal,初始值设为null authState = toSignal(authState(this.angularAuth), { initialValue: null }); constructor(private router: Router, private toastrService: ToastrService) { // 后续会在这里添加状态同步逻辑 } // ...保留其他原有方法 }
2. 用Signal替代isLoggedIn getter
原isLoggedIn是每次访问都会读取localStorage的getter,改为Signal后可以缓存状态,并在用户变化时自动更新。
代码修改:
@Injectable({ providedIn: 'root' }) export class AuthService { private angularAuth = inject(Auth); authState = toSignal(authState(this.angularAuth), { initialValue: null }); // 创建isLoggedIn Signal,初始值从localStorage读取 isLoggedIn = signal(!!localStorage.getItem('user')); constructor(private router: Router, private toastrService: ToastrService) { // 用effect监听authState变化,自动同步localStorage和isLoggedIn状态 effect(() => { const currentUser = this.authState(); if (currentUser) { this.setUser(currentUser); this.isLoggedIn.set(true); } else { localStorage.removeItem('user'); this.isLoggedIn.set(false); } }); } // ...保留其他原有方法 }
3. 简化登录/登出流程的状态更新
因为effect会自动同步authState、localStorage和isLoggedIn,可以移除登录/登出方法中手动更新状态的冗余代码:
修改logIn方法:
logIn(user: LoginUser) { const auth = getAuth(); return from(signInWithEmailAndPassword(auth, user.email, user.password)).pipe( catchError((error: HttpErrorResponse) => { this.handleError(error); return throwError(() => error); }), tap(() => { this.toastrService.success('Successfully logged in', 'Success', { timeOut: 2000, }); this.router.navigate(['/leaderboards']); }) ); }
修改logout方法:
logout() { return from(this.angularAuth.signOut()).pipe( catchError((error: HttpErrorResponse) => { this.handleError(error); return throwError(() => error); }), tap(() => { this.toastrService.success('Successfully logged out', 'Success', { timeOut: 3000, }); this.router.navigate(['/login']); }) ); }
4. 组件中使用Signal示例
在组件里可以直接访问Signal的值,无需使用async管道:
import { Component, inject } from '@angular/core'; import { AuthService } from './auth.service'; @Component({ selector: 'app-header', template: ` <button *ngIf="authService.isLoggedIn()" (click)="authService.logout()">退出登录</button> <a *ngIf="!authService.isLoggedIn()" routerLink="/login">登录</a> ` }) export class HeaderComponent { authService = inject(AuthService); }
内容的提问来源于stack exchange,提问作者gillyweed5
相关产品推荐
相关产品推荐

