You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在现有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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 09:53:20