NgRx http.post 请求在被 Effect 第二次调用后不执行

NgRx http.post request doesn't execute after was call second time by Effect

我在第二次或多次发送登录操作时遇到问题。对于第一个请求,如果登录成功,则一切正常,令牌被获取并且用户被重新路由到主页。如果不成功,您会收到您的登录错误的消息,应该重试,但如果尝试第二次登录 none 请求已发送。

单击按钮 "Login" 后调用的方法是 class "AccountLoginComponent"

中的 onLogin 方法

减速器

import {createEntityAdapter, EntityAdapter, EntityState} from '@ngrx/entity';
import {ActionListModel} from '../models/actionListModel';
import {ActionDetailModel} from '../models/actionDetailModel';
import {createReducer, on} from '@ngrx/store';
import * as ActionActions from './action.actions';

export interface ActionState extends EntityState<ActionListModel> {
  actionDetail: ActionDetailModel,
  messageActionCreation: string,
  actionDetailStatus: string,
  actionListStatus: string,
  actionCreationStatus: string,
}

export function selectActionId(action: ActionListModel): number {
  //In this case this would be optional since primary key is id
  return action.idAction;
}

// we will add entity adapter to our init state
export const adapter: EntityAdapter<ActionListModel> = createEntityAdapter<ActionListModel>({
  selectId: selectActionId
});

// our init state is init state of EntityState
export const initialState: ActionState = {
  ...adapter.getInitialState(),
  actionDetail: null,
  messageActionCreation: "",
  actionListStatus: "",
  actionDetailStatus: "",
  actionCreationStatus: "",
};

const _actionReducer = createReducer(
  initialState,
  on(ActionActions.loadActionsPageSuccess, (state, {actionInList}) => {
    return adapter.addAll(actionInList, state);
  }),
  on(ActionActions.loadActionsPageSuccess, (state, {status}) => ({
    ...state, actionListStatus: status
  })),
  on(ActionActions.loadActionDetailSuccess, (state, {actionDetail}) => ({
    ...state, actionDetail: actionDetail, actionDetailStatus: status
  })),
  on(ActionActions.createAirsoftActionSuccess, (state, {action, status}) => ({
    ...state, actionDetail: action, actionCreationStatus: status,
  }))
);

export function actionReducer(state, action) {
  return _actionReducer(state, action);
}

// get the selectors
const {
  selectIds,
  selectEntities,
  selectAll,
  selectTotal,
} = adapter.getSelectors();

export const selectActionIds = selectIds;

export const selectActionsEntities = selectEntities;

export const selectAllActions = selectAll;

export const selectActionsTotal = selectTotal;

操作

import {createAction, props} from '@ngrx/store';
import {AccountModel} from '../models/account.model';

export enum AccountActionsTypes {
  AccountLogin = '[Login Page] Account Login',
  AccountLoginSuccess = '[Login Page] Account Login Success',
  AccountLoginFailed = '[Login Page] Account Login Failed',

  AccountLogout = '[Header] Account Logout',

  AccountActivation = '[Activation page] Account Activation',
  AccountActivationSuccess = '[Activation page] Account Activation Success',
  AccountActivationFailed = '[Activation page] Account Activation Failed',
}

export const login = createAction(AccountActionsTypes.AccountLogin, props<{ email: string; password: string }>());

export const loginSuccess = createAction(AccountActionsTypes.AccountLoginSuccess, props< { account : AccountModel, token : string, message: string, status: string}>());

export const loginFailed = createAction(AccountActionsTypes.AccountLoginFailed);

export const logout = createAction(AccountActionsTypes.AccountLogout);

export const accountActivation = createAction(AccountActionsTypes.AccountActivation, props<{formula : string}>());

export const accountActivationSuccess = createAction(AccountActionsTypes.AccountActivationSuccess, props<{message : string}>());

export const accountActivationFailed = createAction(AccountActionsTypes.AccountActivationFailed, props<{error : string}>());

效果

login$ = createEffect(() =>
this.actions$.pipe(
  tap( kek => {/*console.log(kek)*/}),
  ofType(AccountActionsTypes.AccountLogin),
  exhaustMap(({email: email, password: password}) => this.accountService.login(email,password)
    .pipe(
      map((response : { body: {account : AccountModel, token : string, message: string, status: string}}) =>
        ({type: AccountActionsTypes.AccountLoginSuccess, account: response.body.account, token: response.body.token, message: response.body.message, status: response.body.status })),
      catchError(error => of({type: AccountActionsTypes.AccountLoginFailed, error: error })),
      tap(response => {
        /*console.log(response)*/;
      }),
    ))
));

服务

private _options = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) };


login(email: string, password: string): Observable<Object> {
        return this.http.post('http://localhost:8080/user/login', {email: email, password: password}, this._options); }

账号登录组件

onLogin() {
    this.store.dispatch(login({email : this.loginForm.value.email, password: sha1(this.loginForm.value.password)}));
    this.loginResult$ = this.store.pipe(select(selectLoginStatus));
    this.loginResultSub = this.loginResult$.subscribe(({loginStatus, message}) => {

      this.isSubscribe = true;
      this.message = message;
      if(loginStatus === 'success') {
        this.router.navigate(['/home']);
      }
    });
  }

问题是因为如果登录错误,我将我状态下的令牌和帐户设置为未定义。我这样修复它:

已修复效果

login$ = createEffect(() =>
this.actions$.pipe(
  ofType(AccountActionsTypes.AccountLogin),
  exhaustMap(({email: email, password: password}) => this.accountService.login(email,password)
    .pipe(
      map((response : { body: {account : AccountModel, token : string, message: string, status: string}}) => {
        if(response.body.token !== undefined) {
          return {type: AccountActionsTypes.AccountLoginSuccess, account: response.body.account, token: response.body.token, message: response.body.message, status: response.body.status };
        } else {
          return {type: AccountActionsTypes.AccountLoginWrong, message: response.body.message, status: response.body.status };
        }
      }),
      catchError(error => of({type: AccountActionsTypes.AccountLoginFailed, error: error })),
    )
  )
));

新动作

export const loginWrong = createAction(AccountActionsTypes.AccountLoginWrong, props< {message: string, status: string}>());

减速器

const _accountReducer = createReducer(
  initialState,
  on(AccountActions.loginSuccess, (state, { account, token, message, status } ) => ({
    ...state, account: account, token: token, message: message, loginStatus: status
  })),
  on(AccountActions.loginWrong, (state, { message, status } ) => ({
    ...state, message: message, loginStatus: status
  })),
  on(AccountActions.logout, (state) => ({
    ...state, account: null, message: "", token: ""
  })),
  on(AccountActions.accountActivationSuccess, (state, { message } ) => ({
    ...state, message: message
  })),
);