成功时,我调度一个Login操作和一个Login Success操作。
登录操作正确触发了reducer。 成功操作具有有效负载时,它不会触发reducer(如果我删除有效负载,但没有用户,它将触发它)。
但是它确实可以正确触发导航效果,并且两个操作在redux开发工具中都是可见的。
成功登录后,我从firebase收到以下错误(即使我从诺言中恢复了用户):
core.js:6382错误TypeError:无法读取未定义的属性“ host” 在Object.push ../ node_modules/@firebase/firestore/dist/index.cjs.js.Firestore.configureClient(http://localhost:4200/vendor.js:120980:33) 在Object.push ../ node_modules/@firebase/firestore/dist/index.cjs.js.Firestore.ensureClientConfigured(http://localhost:4200/vendor.js:120972:18) 在Object.get [as _isTerminated](http://localhost:4200/vendor.js:120926:18) 在http://localhost:4200/vendor.js:128600:37 在Array.forEach() 处于冻结状态(http://localhost:4200/vendor.js:128590:40) 在http://localhost:4200/vendor.js:128603:17 在Array.forEach() 处于冻结状态(http://localhost:4200/vendor.js:128590:40) 在http://localhost:4200/vendor.js:128603:17
动作:
import { createAction, props } from '@ngrx/store';
import { User } from 'firebase';
export const login = createAction('[Authentication/API] Login');
export const loginSuccess = createAction(
'[Authentication/API] Login Success',
props<{ user: User }>()
);
export const loginFail = createAction('[Authentication/API] Login Fail');
效果:
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { map, switchMap, tap, catchError } from 'rxjs/operators';
import { navigate } from 'src/app/store/router';
import * as AuthenticationActions from './authentication.actions';
import { AuthenticationService } from '../services/authentication.service';
import { from, of } from 'rxjs';
@Injectable()
export class AuthenticationEffects {
constructor(
private actions$: Actions,
private authenticationService: AuthenticationService
) {}
login$ = createEffect(() =>
this.actions$.pipe(
ofType(AuthenticationActions.login),
switchMap(() =>
from(this.authenticationService.login()).pipe(
map(({ user }) => AuthenticationActions.loginSuccess({ user })),
catchError(() => of(AuthenticationActions.loginFail()))
)
)
)
);
navigateToDefaultPageOnSuccessfulLogin$ = createEffect(() =>
this.actions$.pipe(
ofType(AuthenticationActions.loginSuccess),
map(() => navigate({ url: 'transactions/import' }))
)
);
}
减速器:
import { Action, createReducer, on } from '@ngrx/store';
import * as AuthenticationActions from './authentication.actions';
import { User } from 'firebase';
export interface AuthenticationState {
user: User | null;
isLoading: boolean;
}
export const initialState: AuthenticationState = {
user: null,
isLoading: false
};
export const authenticationReducer = createReducer<AuthenticationState>(
initialState,
on(AuthenticationActions.login, state => ({ ...state, isLoading: true })),
on(AuthenticationActions.loginSuccess, (state, { user }) => ({
...state,
isLoading: false,
user
})),
on(AuthenticationActions.loginFail, state => ({
...state,
isLoading: false
}))
);
export function reducer(
state: AuthenticationState | undefined,
action: Action
) {
return authenticationReducer(state, action);
}
服务:
import { Injectable } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/auth';
import { auth } from 'firebase/app';
@Injectable({
providedIn: 'root'
})
export class AuthenticationService {
constructor(private afAuth: AngularFireAuth) {}
login() {
return this.afAuth.auth.signInWithPopup(new auth.GoogleAuthProvider());
}
}
答案 0 :(得分:1)
您应将Promise
返回的signInWithPopup
转换为Observable
:
login(): Observable<any> {
const provider = new firebase.auth.GoogleAuthProvider();
return from(this.afAuth.auth.signInWithPopup(provider));
}
我还建议您使用其他方法登录并检索当前已签名的用户:
@Injectable()
export class AuthEffects {
check$ = createEffect(() => this.actions$.pipe(
ofType(authActions.check),
switchMap(() => this.afAuth.authState.pipe(
map(user => user
? authActions.idAuthenticated({ user: user })
: authActions.idNotAuthenticated()
)
))
))
login$ = createEffect(() => this.actions$.pipe(
ofType(authActions.login),
switchMap(() => this.authService.login().pipe(
map(() => authActions.check()),
catchError(error => of(authActions.authError({ message: 'Login failed' })))
))
))
auth.service.ts:
login(): Observable<any> {
const provider = new firebase.auth.GoogleAuthProvider();
return from(this.afAuth.auth.signInWithPopup(provider));
}
}
使用这种体系结构,您可以在初始化应用时调度check
操作。如果用户已经登录,则将检索其凭据。
ngOnInit() {
this.store.dispatch(authActions.check());
}
如果用户尚未登录,则可以导航到错误页面。
请注意您的navigateToDefaultPageOnSuccessfulLogin$
效果,您正在调用不正确的方法来导航到url。
navigateToDefaultPageOnSuccessfulLogin$ = createEffect(() =>
this.actions$.pipe(
ofType(AuthenticationActions.loginSuccess),
map(() => this.router.navigate(['transactions/import' }))
)
);
constructor(private router: Router, ...) {}