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

如何将Firestore/Firebase Auth与Angular的NGXS状态管理器集成?

如何将Firestore/Firebase Auth与NGXS集成(Angular)

作为NGXS和Firebase的新手,我完全理解你找不到集成资料的困惑——毕竟这俩的组合文档确实不算多。下面我就一步步带你实现Firebase Auth和Firestore与NGXS的集成,都是实际项目里能用的方案:

前置准备

首先确保你的Angular项目已经配置好Firebase,同时安装必要的依赖包:

npm install @angular/fire firebase @ngxs/store @ngxs/logger-plugin @ngxs/devtools-plugin

注:logger和devtools插件是可选的,用于调试状态变化,开发阶段很实用

接下来在environment.ts里填入你的Firebase项目配置:

export const environment = {
  production: false,
  firebase: {
    apiKey: "YOUR_API_KEY",
    authDomain: "YOUR_AUTH_DOMAIN",
    projectId: "YOUR_PROJECT_ID",
    storageBucket: "YOUR_STORAGE_BUCKET",
    messagingSenderId: "YOUR_SENDER_ID",
    appId: "YOUR_APP_ID"
  }
};

Firebase Auth 集成步骤

我们先从用户认证开始,核心思路是把Firebase Auth的状态同步到NGXS的state中,并通过actions触发登录、登出等操作。

1. 创建Auth State文件

新建auth.state.ts,先定义状态模型和操作actions:

// 状态模型,保存用户信息、加载状态和错误信息
export interface AuthStateModel {
  user: firebase.User | null;
  loading: boolean;
  error: string | null;
}

// 定义触发状态变化的Actions
export class Login {
  static readonly type = '[Auth] 用户登录';
  constructor(public payload: { email: string; password: string }) {}
}

export class Logout {
  static readonly type = '[Auth] 用户登出';
}

export class AuthStateChanged {
  static readonly type = '[Auth] 认证状态变更';
  constructor(public payload: firebase.User | null) {}
}

然后编写State类,处理Actions并与Firebase Auth交互:

import { State, Action, StateContext, Selector } from '@ngxs/store';
import { AuthStateModel, Login, Logout, AuthStateChanged } from './auth.state';
import { AngularFireAuth } from '@angular/fire/compat/auth';

@State<AuthStateModel>({
  name: 'auth', // state的名称,用于在组件中选择状态
  defaults: {
    user: null,
    loading: false,
    error: null
  }
})
export class AuthState {
  constructor(private afAuth: AngularFireAuth) {}

  // 登录Action:调用Firebase登录API,更新加载状态和错误信息
  @Action(Login)
  login(ctx: StateContext<AuthStateModel>, action: Login) {
    ctx.patchState({ loading: true, error: null });
    return this.afAuth.signInWithEmailAndPassword(action.payload.email, action.payload.password)
      .catch(error => {
        ctx.patchState({ loading: false, error: error.message });
      });
  }

  // 登出Action:调用Firebase登出API,清空用户状态
  @Action(Logout)
  logout(ctx: StateContext<AuthStateModel>) {
    return this.afAuth.signOut()
      .then(() => {
        ctx.patchState({ user: null });
      });
  }

  // 监听Auth状态变更:当Firebase的authState变化时,更新NGXS状态
  @Action(AuthStateChanged)
  authStateChanged(ctx: StateContext<AuthStateModel>, action: AuthStateChanged) {
    ctx.patchState({ user: action.payload, loading: false });
  }

  // 定义Selector,方便组件获取用户信息
  @Selector()
  static getUser(state: AuthStateModel) {
    return state.user;
  }
}

2. 初始化Auth状态监听

在app.component.ts的ngOnInit中监听Firebase Auth的状态变化,并同步到NGXS:

import { Component, OnInit } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/compat/auth';
import { Store } from '@ngxs/store';
import { AuthStateChanged } from './auth.state';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
  constructor(private afAuth: AngularFireAuth, private store: Store) {}

  ngOnInit() {
    // 监听Firebase Auth状态,一旦变化就触发NGXS的Action更新状态
    this.afAuth.authState.subscribe(user => {
      this.store.dispatch(new AuthStateChanged(user));
    });
  }
}

3. 在模块中注册State

最后在app.module.ts中导入必要的模块并注册AuthState:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AngularFireModule } from '@angular/fire/compat';
import { AngularFireAuthModule } from '@angular/fire/compat/auth';
import { NgxsModule } from '@ngxs/store';
import { NgxsLoggerPluginModule } from '@ngxs/logger-plugin';
import { NgxsDevtoolsPluginModule } from '@ngxs/devtools-plugin';

import { AppComponent } from './app.component';
import { AuthState } from './auth.state';
import { environment } from '../environments/environment';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    AngularFireModule.initializeApp(environment.firebase),
    AngularFireAuthModule,
    NgxsModule.forRoot([AuthState]),
    NgxsLoggerPluginModule.forRoot(), // 开发阶段开启,可在控制台查看状态变化
    NgxsDevtoolsPluginModule.forRoot() // 配合Redux Devtools使用
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

Firestore 集成步骤

接下来是Firestore的集成,核心是利用Firestore的实时监听,让NGXS状态自动同步数据库的变化,同时通过Action触发增删改操作。

1. 创建Todo State示例(以Todo列表为例)

新建todo.state.ts,定义状态模型和Actions:

// Todo数据模型
export interface Todo {
  id: string;
  title: string;
  completed: boolean;
}

// Todo状态模型
export interface TodoStateModel {
  todos: Todo[];
  loading: boolean;
  error: string | null;
}

// 定义Actions
export class LoadTodos {
  static readonly type = '[Todo] 加载所有Todo';
}

export class AddTodo {
  static readonly type = '[Todo] 添加新Todo';
  constructor(public payload: Omit<Todo, 'id'>) {}
}

然后编写State类,与Firestore交互:

import { State, Action, StateContext, Selector } from '@ngxs/store';
import { TodoStateModel, LoadTodos, AddTodo, Todo } from './todo.state';
import { AngularFirestore } from '@angular/fire/compat/firestore';
import { map, tap, catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';

@State<TodoStateModel>({
  name: 'todos',
  defaults: {
    todos: [],
    loading: false,
    error: null
  }
})
export class TodoState {
  constructor(private afs: AngularFirestore) {}

  // 加载Todo列表:监听Firestore的实时变化,自动同步状态
  @Action(LoadTodos)
  loadTodos(ctx: StateContext<TodoStateModel>) {
    ctx.patchState({ loading: true, error: null });
    return this.afs.collection<Todo>('todos').snapshotChanges()
      .pipe(
        // 将Firestore的快照转换为我们需要的Todo格式
        map(actions => actions.map(a => {
          const data = a.payload.doc.data() as Omit<Todo, 'id'>;
          const id = a.payload.doc.id;
          return { id, ...data } as Todo;
        })),
        // 更新NGXS状态
        tap(todos => {
          ctx.patchState({ todos, loading: false });
        }),
        // 处理错误
        catchError(error => {
          ctx.patchState({ loading: false, error: error.message });
          return throwError(() => error);
        })
      );
  }

  // 添加Todo:调用Firestore的add方法,由于已经监听了实时变化,状态会自动更新
  @Action(AddTodo)
  addTodo(ctx: StateContext<TodoStateModel>, action: AddTodo) {
    return this.afs.collection<Todo>('todos').add(action.payload);
  }

  // 定义Selector,方便组件获取Todo列表
  @Selector()
  static getTodos(state: TodoStateModel) {
    return state.todos;
  }
}

2. 在模块中注册TodoState

更新app.module.ts,导入AngularFirestoreModule并注册TodoState:

// ... 其他导入
import { AngularFirestoreModule } from '@angular/fire/compat/firestore';
import { TodoState } from './todo.state';

@NgModule({
  imports: [
    // ... 其他模块
    AngularFirestoreModule,
    NgxsModule.forRoot([AuthState, TodoState]) // 添加TodoState
  ]
})
export class AppModule {}

一些实用的最佳实践

  • 利用Selector简化组件状态获取:组件中通过this.store.select(AuthState.getUser)或this.store.select(TodoState.getTodos)来获取状态,无需直接操作state。
  • 使用AuthGuard保护路由:基于NGXS的Auth状态创建路由守卫,比如:
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { Store } from '@ngxs/store';
import { AuthState } from './auth.state';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
  constructor(private store: Store, private router: Router) {}

  canActivate(): Observable<boolean> {
    return this.store.select(AuthState.getUser)
      .pipe(
        map(user => {
          if (!user) {
            this.router.navigate(['/login']);
            return false;
          }
          return true;
        })
      );
  }
}
  • 分离异步逻辑到Effects(可选):如果你的业务逻辑比较复杂,可以使用@ngxs/effects插件将异步操作从State中分离出来,让State更专注于状态更新。
  • 清理订阅:虽然NGXS会自动处理Action中返回的Observable订阅,但如果手动订阅了Firestore的流,记得在组件销毁时取消订阅,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:34:38