I am trying to construct an NgRx
effect and I just cannot see what is wrong in this example (and really want to understand)
I have the following
public loadData = createEffect(() =>
this.actions$
.pipe(
ofType(myActions.loadData),
exhaustMap(_ =>
this.store$.pipe(
tap(_ => { this.logger.info(`loadData`)}),
select(fromApp.getName),
first(),
map(name => {
from(this.getData(name))
.pipe(
map(data => myActions.loadDataSuccess(data)))
}),
catchError(error => {
tap(_ => this.logger.error(`loadData: ${error}`));
return of(new myActions.loadDataError(error));
})
))));
/** Service call **/
private async getData(name: string): Promise<DataState[]> {
...
}
This is how I interpret (obviously wrong somewhere) the flow..
Inside first exhaustMap
, I use the this.store$.pipe
to get an argument I need for my service call. So this the cal tofirst
should return a string
(name).
I then use map
to "map" this string to the from(this.getData(name))
. As my getData
returns a Promise, I use from
to convert to an observable
.
I then pipe
this observable result (an array of data) into another map, where I want to return the effects result, ie an action loadDataSuccess
containing the server results.
The catchError
wants to catch any errors from the map
with the service method call inside of it.
The IDE shows me the following errors
Type 'Observable<unknown>' is not assignable to type 'EffectResult<Action>'.
Type 'Observable<unknown>' is not assignable to type 'Observable<Action>'.
Property 'type' is missing in type '{}' but required in type 'Action'.ts(2322)
I don't know where I have gone wrong (I can't get it right even removing the catchError
)?
Following @Alif50 suggestion to use a switchMap, and also IDE told me to add a return, and removing the catchError
. I now have..
public loadData = createEffect(() =>
this.actions$
.pipe(
ofType(myActions.loadData ),
exhaustMap(_ =>
this.store$.pipe(
tap(_ => { this.logger.info(`loadData`)}),
select(fromApp.getName),
first(),
switchMap(name => {
return from(this.getData(name))
.pipe(map(data => myActions.loadDataSuccess(data)));
}))
)));
which gives no errors, so this is s a step forward, But I am still unable to get the catchError
to work anywhere. So now I just need to know where to add the catchError
?
I think the map
should be a switchMap
since we are switching to a new Observable
.:
map(name => { // change this map to a switchMap
from(this.getData(name))
.pipe(
map(data => myActions.loadDataSuccess(data)))
}),
!!!! Edit !!!!
public loadData = createEffect(() =>
this.actions$
.pipe(
ofType(myActions.loadData ),
exhaustMap(_ =>
this.store$.pipe(
tap(_ => { this.logger.info(`loadData`)}),
select(fromApp.getName),
first(),
switchMap(name => {
return from(this.getData(name))
.pipe(
map(data => myActions.loadDataSuccess(data)),
// add the catchError here because I think this.getData is the point of failure
catchError(error => {
// You also can't have a tap there like you do
// in your catchError
// I would prefer this instead of the tap though
// this.logger.error(`loadData: ${error}`);
return of(new myActions.loadDataError(error)).pipe(
// use tap like this !!
tap(_ => this.logger.error(`loadData: ${error}`))
);
}),
);
}))
)));