2

first of all it is worth mentioning the fact that I still haven't very clear rxjs's operators. I studied them but in the practical act if I either use switchMap, mergeMap or map the result still seems the same.

The code below creates an infinite loop, I tried to place debuggers strategically in order to understand the flow but it must be strictly related to the HTTP response time, hence appears to jump between the effects in a very random way.

@Effect()
addNewDocument = this.actions$.pipe(
    ofType(UserActions.ADD_DOCUMENT),
    map((action: UserActions.AddNewDocument) => {
        return action.document;
    }),
    switchMap((document: FormData) => {
        return this.store.select('user').pipe(
            map((user) => {
                return {
                    document,
                    uuid: user.uuid
                };
            })
        );
    }),
    switchMap((payload: { document: FormData, uuid: string }) => {
        return this.httpClient.post(
            `${environment.apiUrl}user/${payload.uuid}/documents`,
            payload.document
        ).pipe(
            mergeMap((response: any) => {
                return [
                    {
                        type: UserActions.ADDED_DOCUMENT,
                        response
                    }
                ];
            }),
            catchError((error) => of(new AppActions.GenericError(error)))
        );
    })
);

@Effect({dispatch: false})
addedNewDocument = this.actions$.pipe(
    ofType(UserActions.ADDED_DOCUMENT),
    tap(() => {
        this.router.navigate(['/user/documents']);
    })
);

My intent is:

  1. Intercept UserActions.ADD_DOCUMENT action
  2. keep track of the uuid for the http request
  3. Make the request and handle the response through the event UserActions.ADDED_DOCUMENT in order to update the state through its reducer

I'd really appreciate if you help me to understand what's wrong. If you think I missused some operators or you know a better method to use them, please let me know.

Thank you in advance.

5
  • With the caveat that I’m no expert but I think you need to rewrite using following ngrx.io/guide/effects#incorporating-state and pass user through props and possibly the withLatestFrom operator. Commented Jul 14, 2019 at 20:25
  • I didn't know that operator. It'll be very useful. Thank you @AndrewAllen Commented Jul 15, 2019 at 8:06
  • @AdrianBrand Why is that? I'm working at my very first project with NgRx but I think it's cool, I've just found RxJs operator a little difficult to understand as you can see. Commented Jul 15, 2019 at 8:09
  • @zangarmarsh I think Adrian hates the boilerplate problem (he's written his own version of state management) and not all projects need ngrx. Commented Jul 15, 2019 at 8:13
  • I just for the life of me cannot see why people like NgRx, it is insane how much abstraction and boilerplate goes into the simple act of calling an api. It sabotages your velocity and gets in the road at every point. Learn how Angular dependency injection works and how to create sane manageable Angular services. Have a read of my article on Angular state management medium.com/@adrianbrand/… Commented Jul 15, 2019 at 8:17

1 Answer 1

1

It appears that your user state is changing in your application which is causing the looping in the effect. Try using take(1) while taking user state in effect like this:

switchMap((document: FormData) => {
        return this.store.select('user').pipe(
            take(1),
            map((user) => {
                return {
                    document,
                    uuid: user.uuid
                };
            })
        );
    })

take(1) will complete the observable and will tear down the action until the next UserActions.ADD_DOCUMENT action dispatched. Hope it helps.

Sign up to request clarification or add additional context in comments.

6 Comments

Not necessarily that the user is changing but that when the state changes the selector fires?
Yes, if user state changes, the selector will emit the new user state.
How come the operator should be triggered as the user state changes?
@zangarmarsh That's because in ngrx effects are subscribed by the library and because of state changes, it will trigger the selector. Is the solution worked for you?
Thank you very much, it worked @user2216584 . I don't really get what brings on the loop tho. Is the 'select' method that fires every time the state changes?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.