Home > Software engineering >  Action and Effects are not giving the Array of Objects
Action and Effects are not giving the Array of Objects

Time:12-22

I am trying to fetch an array of objects that is into User. I have created an Action and an Effect.

The User Model it is like this.

export interface User {
_id: string,
firstName: string,
lastName: string,
jobs?: UserJobs[];
}


 export interface UserJobs {
  jobId?: string;
  timestamp?: Date;
}

And into UserJobs there are 2 objects.
[{"timestamp":"2022-10-05T21:21:24.917Z","jobId":"633df55439b18b2937a21ffd"},
{"timestamp":"2022-11-08T20:10:03.952Z","jobId":"636ab79b64211425baaf98e6"}]

But still on the Redux Dev tools I am getting nothing. I am getting this error on the console.

ERROR Error: Effect "JobsStateEffects.loadUserJob$" dispatched an invalid action: [{"timestamp":"2022-10-05T21:21:24.917Z","jobId":"633df55439b18b2937a21ffd"},{"timestamp":"2022-11-08T20:10:03.952Z","jobId":"636ab79b64211425baaf98e6"}]

And below i am getting like this.

ERROR TypeError: Actions must have a type property

Action.ts

export const userLoadJobs = createAction(
  '[UserJobs] userLoadJobs',
);

Effect.ts

  loadUserJob$ = createEffect(() => 
    this.actions$.pipe(
      ofType(userLoadJobs),
      exhaustMap(action => 
      // Here If I use action it shows then nothing because my Service it is waiting for an ID      this.userService.getUserContactData(this.authService.userID).pipe(
          map(payload => payload)
        )
      )
    )
  )

This is the store select

export const jobsStateFeatureKey = 'jobState';

export interface AppState {
  jobState: InitialState;
}

export const selectJobsStateState = createFeatureSelector<InitialState>(
    jobsStateFeatureKey
);

export const selectUserJobs = createSelector(
      selectJobsStateState,
      (state: InitialState) => state.jobs
    )

Reducers.ts

export interface InitialState {
  job: Job;
  user: User,
  loading: boolean;
  error: unknown;
  jobs: UserJobs[];

}

export const initialState: InitialState = {
  job: new Job(),
  user: new User(),
  jobs: [],
  loading: false,
  error: undefined
};

const appReducer = createReducer(
  initialState,
  on(
    jobLoaded,
    userLoadJobs,
    updateJob,
    state => ({
      ...state,
      loading: true
    })
  ),
  
  on(JobsStateActions.jobLoaded, (state, action) => {
    const job = action.job;
    const loading = false;
    return {...state, job, loading};
  }),

   on(JobsStateActions.userLoadJobs, (state) => {
return {...state};

}),

export function todoReducer(
  state: InitialState | undefined,
  action: Action
) {
  return appReducer(state, action);
}

This is the component

  userJobs$: Observable<UserJobs[]> = this.store.select(selectUserJobs);
   ngOnInit(): void {
    this.store.dispatch({ type: '[UserJobs] userLoadJobs' });
  }

CodePudding user response:

1- We get the data from the service into a pipe because it's observable

2- The effect dispatch the result (data) via action.

3- We create a reducer to get the data from the action to the store (do you use any reducer in the project? it's not clear in the question)

Here's an example how the effect reflex the result as an action:

  loadData$ = createEffect(() => this.actions$.pipe(
    ofType(userLoadJobs),
    mergeMap(() => this.dataService.getAll()
      .pipe(
        map(data => ({ type: '[Data API] Data Loaded Success', payload: data })),
        catchError(() => EMPTY)
      ))
    )
  );

CodePudding user response:

If you take a closer look at the error you can see that the error is coming from the effects.

 loadUserJob$ = createEffect(() => 
    this.actions$.pipe(
      ofType(userLoadJobs),
      exhaustMap(action => 
      // Here If I use action it shows then nothing because my Service it is waiting for an ID      this.userService.getUserContactData(this.authService.userID).pipe(
          map(payload => payload)
        )
      )
    )
  )

This is because the effect will dispatch the result to the store. In this case the payload. Because payload is not an NgRx action, it will throw the error. As a fix, you should return an action instead of map(payload => payload). If the effect doesn't need to return an action, and just invoke a service make it a non-dispatching effect (which means that the effect does not dispatch to the store). https://ngrx.io/guide/effects/lifecycle#non-dispatching-effects

To dispatch an action, define the action and return it from the effect.

import {createAction, props} from '@ngrx/store';

export const userLoadJobsSuccess = createAction(
  '[UserJobs] userLoadJobs Success',
   props<{payload: any}>()
);

----

  loadUserJob$ = createEffect(() => 
    this.actions$.pipe(
      ofType(userLoadJobs),
      exhaustMap(action => 
      // Here If I use action it shows then nothing because my Service it is waiting for an ID      this.userService.getUserContactData(this.authService.userID).pipe(
          map(payload => userLoadJobsSuccess(payload))
        )
      )
    )
  )
  • Related