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))
)
)
)
)