简体   繁体   中英

What is the better way to cancel a ngrx effect service call, based on a validation in the effect?

I have this ngrx effect that is calling in this example to movies service, but is depending of a value selector, if this values is as expected in validation, the effect sould send a new action, this way I avoid to call the service because the condition. Right now I cannot use another action (this would be more descriptive) in the if block because of this error:

Type 'Observable' is not assignable to type 'Observable | ((...args: any[]) => Observable)'.

Type 'Observable' is not assignable to type 'Observable'.ts(2322).

What is the better way to handle this scenario?

loadMovies$ = createEffect(() => this.actions$.pipe(
        ofType('[Movies Page] Load Movies'),
        concatMap(action => of(action).pipe(withLatestFrom(this.store.select(getBlockBuster)))),
        mergeMap(([{payload}, foundBlockBuster]) => {
            if (!foundBlockBuster) {
                // in order to avoid errors we need to use this({ type: '[Movies API] Movies Loaded Success', payload: movies }))
                return of({ type: '[Movies] The block busters are rent' })
            }
            return this.moviesService.getAll()
                .pipe(
                    map(movies => ({ type: '[Movies API] Movies Loaded Success', payload: movies })),
                    catchError(() => of({ type: '[Movies API] Movies Loaded Error' }))
                )
            })
        )
    );

This error is happening because you should return Observable<action> instead your code is returning two types of object literal (assumed as it is of type Action ) one which has only type property and another one has type and payload . To fix this error have an array of Action and then push your object literal in that array and then return that array like this:

loadMovies$ = createEffect(() => this.actions$.pipe(
        ofType('[Movies Page] Load Movies'),
        concatMap(action => of(action).pipe(withLatestFrom(this.store.select(getBlockBuster)))),
        mergeMap(([{payload}, foundBlockBuster]) => {

            const actions = new Array<Action>();

            if (!foundBlockBuster) {
                actions.push({ type: '[Movies] The block busters are rent' });
                return actions;                
            }
            return this.moviesService.getAll()
                .pipe(
                    mergeMap(movies => {
                      actions.push({ type: '[Movies API] Movies Loaded Success', payload: movies });
                      return actions;
                    }),
                    catchError(() => {
                      actions.push({ type: '[Movies API] Movies Loaded Error' });
                      return actions;
                    })
                )
            })
        )
    );

Alternatively, you can typecast your object literals as <Action> like this:

<Action>{ type: '[Movies] The block busters are rent' }

But I prefer to use the array as array allows to dispatch multiple actions if my app logic needs so.

Hope it helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM