Francisco Souza
Francisco Souza

Reputation: 828

Reducer error always undefined when passing wrong URL in NgRx in Ionic 3

Could someone help me to see what's wrong here that every time I try to cause an error I get: core.js:12632 ERROR TypeError: Cannot read property 'error' of undefined

My Effect:

  @Effect() loadByEmail = this.actions
    .pipe(
      ofType(ProfileActions.ActionTypes.Begin),
      map((action: ProfileActions.LoadProfileBegin) => action),
      switchMap(action => this.service.loadByEmail(action.email, true)),
      map(response => ({
        type: ProfileActions.ActionTypes.Success,
        payload: response,
        error: null
      })),
      catchError((error) => of ({
        type: ProfileActions.ActionTypes.Failure,
        error: error
      }))
    );

The reducer:

export interface ProfileState {
  payload: any;
  loading: boolean;
  error: any;
}

const initialState: ProfileState = {
  loading: false,
  error: null,
  payload: null
};

export function profileReducer(state = initialState, action: profileActions.ActionsUnion): ProfileState {
  switch (action.type) {

    case profileActions.ActionTypes.Begin: {
      return {
        ...state,
        loading: true,
        error: null
      };
    }

    case profileActions.ActionTypes.Success: {
      return {
        ...state,
        loading: false,
        payload: action.payload.data
      };
    }

    case profileActions.ActionTypes.Failure: {
      return {
        ...state,
        loading: false,
        error: action.payload.error /* this is the line 49*/
      };
    }

    default: {
      return state;
    }
  }
}

export const getProfile = (state: ProfileState) => state.payload;

I think I might be doing some big mistake here that causes this problem, I need to capture the error when subscribing.

Here are the actions, actually it's a very basic stuff, it's just a flow to load a profile from the web service by an email address.

Here are the three actions:

export enum ActionTypes {
  Begin = "[Profile] Load data begin",
    Success = "[Profile] Load data success",
    Failure = "[Profile] Load data failure"
}

export class LoadProfileBegin implements Action {
  readonly type = ActionTypes.Begin;
  constructor(public email: string) {}
}

/**
 * The main thing to note here is that our LoadDataSuccess and 
 * LoadDataFailure actions will include a payload - we will either 
 * pass the loaded data along with LoadDataSuccess or we will 
 * pass the error to LoadDataFailure.
 */
export class LoadProfileSuccess implements Action {
  readonly type = ActionTypes.Success;

  constructor(public payload: {
    data: any
  }) { }
}

export class LoadProfileFailure implements Action {
  readonly type = ActionTypes.Failure;

  constructor(public payload: {
    error: any
  }) { }
}

export type ActionsUnion = LoadProfileBegin | LoadProfileSuccess | LoadProfileFailure;

Then I have a service to call a rest service which will return an Observable to the Effect:

  public loadByEmail(email: string, showLoading ? : boolean): Observable < any > {
    const data: any = {
      'email': email
    };
    return <Observable < any >> this.restService.sendPost('profiles__/find-by-email', data);
  }

Then I have two methods: one to dispatch the action and the other to return the state:

  loadProfileState(email: string) {
    this.store.dispatch(new ProfileActions.LoadProfileBegin(email));
  }

  getProfileState(): Store < ProfileState > {
    return this.store.select(getProfileState);
  }

And then in some component I subscribe trying to catch the error:

this.profileService.getProfileState().subscribe(state => {
  if (state.payload) {
    const profile = state.payload.json;
    this.setProfileData(profile, true);
  } 

  if (state.error){
    // This one here never reaches
  }
});

As you can see on the image below the error happens but never capture and passed using the action: enter image description here

I know it's a lot but if someone could notice anything and point it to me I would appreciate very much.

Upvotes: 0

Views: 158

Answers (1)

user2216584
user2216584

Reputation: 5602

I doubt that your reducer is being called when your effect "catchError" operator returns of(....). In fact, you must return an action like -

@Effect() loadByEmail = this.actions
    .pipe(
      ofType(ProfileActions.ActionTypes.Begin),
      map((action: ProfileActions.LoadProfileBegin) => action),
      switchMap(action => this.service.loadByEmail(action.email, true)),
      map(response => ({
        type: ProfileActions.ActionTypes.Success,
        payload: response,
        error: null
      })),
      catchError((error) => [new ProfileActions.LoadProfileFailure({error})])
    );

Upvotes: 1

Related Questions