Ngrx SignalStore服务更新状态,组件/守卫无法获取更新值
问题根源与解决方案
核心问题分析
你遇到的是依赖注入实例不共享 + 异步状态未等待的组合问题:
1. 依赖注入实例冲突
你的AuthComponent组件元数据中添加了providers: [AuthStore],这会导致组件创建一个独立的AuthStore实例,而FirebaseService和AuthGuard注入的是root级别的全局实例。两者状态完全隔离,所以:
FirebaseService更新的是全局实例的用户状态,能在服务内打印出正确值- 组件和Guard分别使用自己的实例,自然获取不到更新后的用户数据
2. Guard的异步状态未处理
Firebase的onAuthStateChanged是异步触发的,当Guard同步调用authStore.user()时,认证状态可能还没初始化完成,此时会误判用户未登录。
分步解决方案
第一步:修复实例共享问题
移除AuthComponent的providers数组中的AuthStore,确保整个应用共用同一个全局AuthStore实例:
@Component({ selector: 'app-auth', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: ` <div class=""> <div class=""> <h1 class="">Log In</h1> <div> <label>Email</label> <input [(ngModel)]="email" class="" type="email" placeholder="Your email" /> </div> <div> <label>Password</label> <input [(ngModel)]="password" class="" type="password" placeholder="Password" /> </div> <div> <button (click)="onSubmit()" type="submit" class="" [disabled]="loading" > {{ loading ? 'Loading' : 'Log In' }} </button> </div> <div>{{ store.user() ?? 'null' }}</div> </div> </div>`, imports: [CommonModule, FormsModule], // 移除这一行:providers: [AuthStore] }) export class AuthComponent { // 组件代码不变 }
第二步:处理Guard的异步认证状态
将AuthGuard改为异步函数,等待Firebase认证状态初始化完成后再判断:
import { inject } from '@angular/core'; import { CanActivateFn, Router } from '@angular/router'; import { AuthStore } from './components/auth/auth-store'; import { getAuth, onAuthStateChanged } from '@angular/fire/auth'; import { firstValueFrom } from 'rxjs'; export const AuthGuard: CanActivateFn = async () => { const router = inject(Router); const authStore = inject(AuthStore); const auth = getAuth(); // 等待Firebase认证状态初始化完成 await firstValueFrom(new Promise(resolve => onAuthStateChanged(auth, resolve))); const user = authStore.user(); if (!user) { router.navigate(['login']); return false; } return true; };
可选优化:在AuthStore中封装初始化逻辑
为了更优雅地处理状态等待,可以在AuthStore中添加一个初始化方法:
export const AuthStore = signalStore( { providedIn: 'root' }, withState(initialState), withMethods((store) => ({ updateUser(user: User | null): void { patchState(store, () => ({ user })); }, // 添加等待认证初始化的方法 async waitForAuthInit(): Promise<User | null> { const auth = getAuth(); await firstValueFrom(new Promise(resolve => onAuthStateChanged(auth, resolve))); return store.user(); } })) );
然后在Guard中调用:
export const AuthGuard: CanActivateFn = async () => { const router = inject(Router); const authStore = inject(AuthStore); const user = await authStore.waitForAuthInit(); if (!user) { router.navigate(['login']); return false; } return true; };
内容的提问来源于stack exchange,提问作者David McGhee
相关产品推荐
相关产品推荐

