Ondřej Bauer
Ondřej Bauer

Reputation: 91

ngrx action is called without calling it in effect

I have made a effect to load data and actions to load, load success and load failure. Effect is working but it calls both actions(success, failure) but I returned just load success. If I move failure reducer above success it calls first failure and then success and similary if i switch them. I didn`t dispatch any of them somewhere else. What am I doing wrong?

loadFilteredElements$ = createEffect(() =>
    this.actions$.pipe(
        ofType(loadFilteredElements),
        switchMap((action) => this.elementsService.getFilteredElementsForProject(action.filter)),
        map((data) => loadFilteredElementsSuccess(data.values!))
    )
);
on(ElementActions.loadFilteredElementsSuccess, (state: ElementState, { elements }) =>{ 
    console.log('succes action');

    return ({
    ...state,
    elements: elements,
    error: undefined,
    status: StatusEnum.success,
})}),
on(ElementActions.loadFilteredElementsFailure, (state: ElementState, { error }) =>{
    console.log('failure');

    return  ({
    ...state,
    status: StatusEnum.error,
    error: error,
})}),
on(ElementActions.changeElementFilter, (state: ElementState, { filter }) =>{
    console.log('changefilter');

    return ({
    ...state,
    filter: filter,
})})
export const loadFilteredElements = createAction('[Element[]] load elements from server', (filter: ElementFilter) => ({
    filter,
}));

export const loadFilteredElementsSuccess = createAction(
    '[Elements[] API] elements succesfully loaded',
    (elements: AppElement[]) => ({ elements })
);

export const loadFilteredElementsFailure = createAction(
    '[Elements[] API] elements succesfully loaded',
    (error: ResponseResultEnum) => ({ error })
);

Upvotes: 0

Views: 1810

Answers (2)

acandylevey
acandylevey

Reputation: 326

Looks like your failure action is using the same type as your success action, so infact you have declared the same action twice.

Change

export const loadFilteredElementsSuccess = createAction(
    '[Elements[] API] elements succesfully loaded',
    (elements: AppElement[]) => ({ elements })
);

export const loadFilteredElementsFailure = createAction(
    '[Elements[] API] elements succesfully loaded',
    (error: ResponseResultEnum) => ({ error })
);

to

export const loadFilteredElementsSuccess = createAction(
    '[Elements[] API] elements succesfully loaded',
    (elements: AppElement[]) => ({ elements })
);

export const loadFilteredElementsFailure = createAction(
    '[Elements[] API] elements failed to load',
    (error: ResponseResultEnum) => ({ error })
);

Upvotes: 2

Amer
Amer

Reputation: 6706

The NgRx Effect dispatches an action by default, if you didn't change that.

So, any action returned from the effect stream (using map operator) is then dispatched back to the Store.

As described in @ngrx/effects docs:

Metadata is attached to the observable streams using the createEffect function. The metadata is used to register the streams that are subscribed to the store. Any action returned from the effect stream is then dispatched back to the Store.

To change this behavior, add { dispatch: false } to the createEffect function as the second argument, like the following:

loadFilteredElements$ = createEffect(
    () =>
        this.actions$.pipe(
            ofType(loadFilteredElements),
            switchMap((action) => this.elementsService.getFilteredElementsForProject(action.filter)),
            map((data) => loadFilteredElementsSuccess(data.values!))
        ),
    { dispatch: false }
);

Upvotes: 0

Related Questions