动作已正确调度,但减速器未调用

时间:2019-12-16 15:30:47

标签: angular firebase ngrx

成功时,我调度一个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());
  }
}

1 个答案:

答案 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, ...) {}
相关问题