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

Angular 16:如何用Signals/Effects实现无订阅API调用与登录跳转

基于Angular 16 Signals实现无订阅登录流程

核心思路

用Angular 16的signal存储登录状态、表单数据等状态值,通过effect监听状态变化自动执行跳转逻辑,结合firstValueFrom将Observable风格的API转为Promise,用async/await处理异步操作,完全避免手动订阅。


1. 全局登录状态管理(AuthService)

先实现一个全局AuthService,统一处理登录逻辑和状态管理:

import { Injectable, signal, effect, inject } from '@angular/core';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { firstValueFrom } from 'rxjs';

// 定义用户类型
interface User {
  id: string;
  email: string;
  token: string;
}

@Injectable({ providedIn: 'root' })
export class AuthService {
  private http = inject(HttpClient);
  private router = inject(Router);

  // 登录状态Signal
  isLoggedIn = signal(false);
  // 当前用户信息Signal
  currentUser = signal<User | null>(null);

  constructor() {
    // 监听登录状态变化,自动跳转到首页
    effect(() => {
      if (this.isLoggedIn()) {
        this.router.navigate(['/home']);
      }
    });
  }

  // 谷歌登录逻辑
  async googleLogin(): Promise<User> {
    try {
      // 调用后端谷歌登录API,转为Promise处理
      const user = await firstValueFrom(
        this.http.post<User>('/api/auth/google', {})
      );
      // 更新状态Signal
      this.currentUser.set(user);
      this.isLoggedIn.set(true);
      return user;
    } catch (error) {
      throw new Error('谷歌登录失败');
    }
  }

  // 邮箱登录逻辑
  async emailLogin(email: string, password: string): Promise<User> {
    try {
      const user = await firstValueFrom(
        this.http.post<User>('/api/auth/email', { email, password })
      );
      this.currentUser.set(user);
      this.isLoggedIn.set(true);
      return user;
    } catch (error) {
      throw new Error('邮箱登录失败,请检查账号密码');
    }
  }
}

2. 登录组件实现(LoginComponent)

组件负责收集表单数据,触发登录操作,无需处理订阅和跳转逻辑:

import { Component, signal, inject } from '@angular/core';
import { AuthService } from './auth.service';

@Component({
  selector: 'app-login',
  template: `
    <div class="login-container">
      <!-- 谷歌登录按钮 -->
      <button (click)="handleGoogleLogin()" class="google-btn">谷歌登录</button>

      <!-- 邮箱登录表单 -->
      <div class="email-form">
        <input 
          type="email" 
          placeholder="邮箱"
          [value]="emailForm().email"
          (input)="updateForm('email', $event.target.value)"
        >
        <input 
          type="password" 
          placeholder="密码"
          [value]="emailForm().password"
          (input)="updateForm('password', $event.target.value)"
        >
        <button (click)="handleEmailLogin()" class="email-btn">登录</button>
      </div>
    </div>
  `
})
export class LoginComponent {
  private authService = inject(AuthService);

  // 邮箱登录表单数据Signal
  emailForm = signal({ email: '', password: '' });

  // 更新表单字段
  updateForm(field: 'email' | 'password', value: string) {
    this.emailForm.update(prev => ({ ...prev, [field]: value }));
  }

  // 触发谷歌登录
  async handleGoogleLogin() {
    try {
      await this.authService.googleLogin();
    } catch (error) {
      alert(error.message);
    }
  }

  // 触发邮箱登录
  async handleEmailLogin() {
    const { email, password } = this.emailForm();
    if (!email || !password) {
      alert('请填写完整账号密码');
      return;
    }
    try {
      await this.authService.emailLogin(email, password);
    } catch (error) {
      alert(error.message);
    }
  }
}

关键要点说明

  • Signal替代订阅:用signal存储状态,状态变化会自动通知依赖它的effect,无需手动订阅Observable
  • Effect自动处理副作用:登录状态变化时,effect自动触发跳转,把副作用逻辑从组件分离到服务中
  • 无订阅异步处理:用firstValueFrom将Observable风格的HTTP请求转为Promise,结合async/await处理异步,彻底告别subscribe
  • 表单状态管理:用signal存储表单数据,通过update方法修改状态,替代双向绑定或表单控件订阅

内容的提问来源于stack exchange,提问作者Spring

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 10:45:04