Angular Ngrx+Firebase OAuth:触发GetUser动作但Effect未执行
GetUser未触发的问题 根据你描述的情况——登出流程能正常触发GetUser对应的Effect,但登录流程中GetUser action明明在DevTools里可见,Effect却毫无反应,且仅离线时正常——我来帮你梳理几个最可能的原因和解决思路:
1. 修正authState的订阅逻辑
Firebase的authState是一个持续的Observable(类似BehaviorSubject),如果你的GetUser Effect直接返回它而不做终止处理,可能会导致流一直处于订阅状态,后续的GET_USER action会被switchMap取消之前的订阅,但这不应该导致console.log('test')不执行。不过可以先修改逻辑,确保我们只取当前的用户状态一次:
@Effect() getUser: Observable<Action> = this.actions.ofType(UserActions.GET_USER) .pipe( switchMap(() => { console.log('test'); // 现在应该能执行了 return this.afAuth.authState.pipe(take(1)); // 添加take(1),只取当前值后结束流 }), map(user => { return user ? new UserActions.Authenticated(user) : new UserActions.Unauthenticated(); }), catchError(err => of(new UserActions.AuthError({error: err.message}))) );
2. 优化登录Effect的异步流处理
你的登录Effect用Observable.fromPromise包装了登录Promise,但Promise完成后流就结束了。在线时Firebase的认证流程存在延迟,可能导致authState还没更新就发出了GetUser action。可以直接在登录成功后订阅authState,跳过中间的GetUser action,避免时机问题:
@Effect() googleLogin: Observable<Action> = this.actions.ofType(UserActions.GOOGLE_LOGIN) .pipe( switchMap(() => from(this.loginWithGoogle())), switchMap(() => this.afAuth.authState.pipe(take(1))), map(user => new UserActions.Authenticated(user)), catchError(err => of(new UserActions.AuthError({error: err.message}))) ); private loginWithGoogle() { return this.afAuth.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider()); }
3. 排查Action的传播问题
既然DevTools能看到GetUser action,但Effect没响应,要确认:
UserActions.GET_USER的字符串常量和Effect中ofType的参数完全一致(大小写、拼写都要检查,虽然登出时正常,但在线场景可能有隐藏的不一致);- 你的
GetUserEffect已经正确注册到EffectsModule中(比如EffectsModule.forRoot([UserEffects])或对应的feature模块); - 没有meta-reducer(比如日志、过滤类)阻止了
GET_USERaction的传播。
4. 考虑Firebase在线状态下的异步延迟
在线时,Firebase的signInWithPopup需要和Google服务器交互,认证完成后还会同步用户数据,导致authState的更新有轻微延迟。如果你的GetUser Effect订阅authState时状态还没更新,可能会出现看似没触发的情况,但console.log应该还是会执行的。添加take(1)和错误捕获后,应该能看到具体的问题。
内容的提问来源于stack exchange,提问作者Leon Marzahn

