The ngrx effect is not called when an action is dispatched from a component

I had a problem with the ngrx repository not sending an action that is supposed to deal with it.

Here is the component that is trying to send:

signin() { this.formStatus.submitted = true; if (this.formStatus.form.valid) { this.store.dispatch(new StandardSigninAction(this.formStatus.form.value.credentials)); } } 

Actions:

 export const ActionTypes = { STANDARD_SIGNIN: type('[Session] Standard Signin'), LOAD_PERSONAL_INFO: type('[Session] Load Personal Info'), LOAD_USER_ACCOUNT: type('[Session] Load User Account'), RELOAD_PERSONAL_INFO: type('[Session] Reload Personal Info'), CLEAR_USER_ACCOUNT: type('[Session] Clear User Account') }; export class StandardSigninAction implements Action { type = ActionTypes.STANDARD_SIGNIN; constructor(public payload: Credentials) { } } ... export type Actions = StandardSigninAction | LoadPersonalInfoAction | ClearUserAccountAction | ReloadPersonalInfoAction | LoadUserAccountAction; 

Effect:

  @Effect() standardSignin$: Observable<Action> = this.actions$ .ofType(session.ActionTypes.STANDARD_SIGNIN) .map((action: StandardSigninAction) => action.payload) .switchMap((credentials: Credentials) => this.sessionSigninService.signin(credentials) .map(sessionToken => { return new LoadPersonalInfoAction(sessionToken); }) ); 

In debugging, I see the component calling the submit method. I can also confirm that the StandardSigninAction actually created because the breakpoint in the constructor hits.

But the effect of standardSignin$ not called ...

What can cause the effect?

How can I debug what is happening in the store?

Can anybody help?

PS I perform the above effect as follows in my import:

 EffectsModule.run(SessionEffects), 

to change . Here is my SessionSigninService.signin method (returns the return value)

  signin(credentials: Credentials) { const headers = new Headers({'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}); const options = new RequestOptions({headers: headers}); const body = 'username=' + credentials.username + '&password=' + credentials.password; return this.http.post(this.urls.AUTHENTICATION.SIGNIN, body, options).map(res => res.headers.get('x-auth-token')); } 
+15
source share
4 answers

This will not be the final answer, but hopefully it will be helpful.

Before you begin:

  • Make sure you are using the latest versions of @ngrx packages (which are appropriate for your version of Angular).
  • If you have updated any packages, make sure that you restart the development environment (that is, reboot the node, server, etc.).

If you haven’t done this yet, you should take a look at the implementation of the Store — so that you make some educated guesses about what might go wrong. Note that the Store pretty bright. This is both an observable (using the state as its source) and an observer (which reports to the dispatcher).

If you look at store.dispatch , you will see that it is an alias for store.next that calls next on Dispatcher .

Therefore, the call:

 this.store.dispatch(new StandardSigninAction(this.formStatus.form.value.credentials)); 

you just need to see the action emitted by the dispatcher.

The observed Actions , which is introduced into your effects, are also quite easy. This is just an observable that uses Dispatcher as its source.

To look at the actions flowing through the effect, you can replace this:

 @Effect() standardSignin$: Observable<Action> = this.actions$ .ofType(session.ActionTypes.STANDARD_SIGNIN) 

with this:

 @Effect() standardSignin$: Observable<Action> = this.actions$ .do((action) => console.log(`Received ${action.type}`)) .filter((action) => action.type === session.ActionTypes.STANDARD_SIGNIN) 

ofType not an operator; this is a method, so to add a do log, you need to replace it with filter .

When you log into the system, if you get an action, something is wrong with the effect (or maybe the lines / constants of the types of actions are not what you think, but something is incompatible).

If the effect does not receive the dispatched action, the most likely explanation would be that the Store through which you send the StandardSigninAction is not the same Store that uses your effect - that is, you have a problem with the DI.

If so, you should look at what is different from the other SessionEffects , which, as you say, works. (At least you have something working, which is a good place to start experiments.) Are they sent from another module? The module that sends the StandardSigninAction function module?

What happens if you hack one of the SessionEffects workers to replace its submitted action with StandardSigninAction ? Is the effect performed?

Please note that the questions at the end of this answer are not questions I want to answer; these are questions that you should ask yourself and research.

+16
source

Your storage thread may stop due to unhandled errors or possibly more obscure errors that appear to be handled with .catch , which actually kill the thread without reusing the new Observable to continue.

For example, this will destroy the stream:

 this.actions$ .ofType('FETCH') .map(a => a.payload) .switchMap(query => this.apiService.fetch$(query) .map(result => ({ type: 'SUCCESS', payload: result })) .catch(err => console.log(`oops: ${err}`))) // <- breaks stream! 

But it will save a life:

 this.actions$ .ofType('FETCH') .map(a => a.payload) .switchMap(query => this.apiService.fetch$(query) .map(result => ({ type: 'SUCCESS', payload: result })) .catch(e => Observable.of({ type: 'FAIL', payload: e}))) // re-emit 

This is true for any rxjs Observable btw, which is especially important to consider when broadcasting to multiple observers (for example, the ngrx store makes internal use of the internal Subject ).

+7
source

I am using a later version of ngrx (7.4.0), so the suggestion of a cartridge is:

 .do((action) => console.log('Received ${action.type}')) 

should be ...

 ... = this.actions.pipe( tap((action) => console.log('Received ${action.type}')), ... 

And in the end, I found that I missed adding my new export of effects to the module, for example:

 EffectsModule.forRoot([AuthEffects, ViewEffects]), // was missing the ', ViewEffects' 
+1
source

Another possible reason is that if you used ng generate to create a module into which you imported effects, make sure it is imported into the application module, because the following command “ng generate module myModule” will not add it to the application module.

0
source

Source: https://habr.com/ru/post/1265845/


All Articles