Reputation: 11
After getting data with subscribe, I want to dispatch actions as below. But both subscribe and dispatch are executed asynchronously, where no chain is forced bet. subscribe and dispatch. Also not possible to describe dispatch inside subscribe so that would cause infinite loop.
What is a better way to dispatch actions when I get a certain data from subscription?
My current code is,
// MyApp.ts
ngOnInit() {
this.store.subscribe(appState => {
this.userId = ppState.currentUserId;
)};
this.store.dispatch(new LoadInitialData(this.userId);
data$ = this.store.select('data');
}
My possible solution is just to implement into @Effect()...
// MyApp.ts
ngOnInit() {
this.store.dispatch(new LoadUserId());
}
//MyEffectService.ts
@Effect() loadUserId$ = this.actions$
.ofType(LOAD_USER_ID)
.withLatestFrom(this.store.select('userId')
.map([any, userId] => userId)
.map(userId => new LoadInitialData(userId));
Upvotes: 1
Views: 2968
Reputation: 6300
The "possible" solution you mentioned looks fine.
It's a good practice to keep your smart component (or container) simple, without too many business logic.
It's why, I would suggest you to rename your action to "Load" or "InitView", "Open"... to better match the real action. (here initialization of view, or view opening...). In the future, you could imagine do more things (than just load user data...) when component is initialized. Your code inside component will stay simple with only one action dispatched. Business logic remains inside your effect.
About that, have a look at this good conference from Mike Ryan : Good Action Hygiene with NgRx
Then, it sounds perfectly good to use an effect to dispatch another action (load needed data...).
Example (without new effect/action creator syntax) :
// MyApp.ts
ngOnInit() {
this.store.dispatch(new Init());
}
// MyEffectService.ts
@Effect()
init$ = this.actions$
.ofType(Init)
.withLatestFrom(this.store.select(selectors.getUserId)
.map([any, userId] => userId)
.map(userId => new LoadInitialData(userId));
PS: An other good practice is also to always use selector
to retrieve a slice of your state. (in the example above, I used selectors.getUserId
)
Upvotes: 0
Reputation: 1431
Use set Immediate it should dispatch event last in the loop
this.store.subscribe(appState =>
setImmediate(() => {
this.userId = ppState.currentUserId
this.store.dispatch(new LoadInitialData(this.userId)
})
))
Upvotes: 0
Reputation: 17909
this.store
.map(appState => ppState.currentUserId)
.do(userId => this.store.dispatch(new LoadInitialData(userId))
.subscribe(userId => this.userId = userId);
Upvotes: 2