I've moved from imperative actions to purely past-tense actions, and I really like how it moves app intelligence out of my components and into my Effects. I used to use something like...
this.store.dispatch(MemberActions.loadMembers());
...in my MemberListComponent, but with a filter on whether the data was currently loading or already loaded, etc.
Now, I'm trying the following in my component...
this.store.dispatch(MemberActions.memberListInitialized());
with the following effect...
getAllMembers$ = createEffect(
() => this.actions$
.pipe(
ofType(MemberActions.memberListInitialized),
concatLatestFrom(() => this.store.select(MemberSelectors.isLoaded)),
filter(([action, loaded]) => !loaded),
switchMap(action => {
return this.memberService.getAll();
}),
map((members) => MemberActions.membersLoaded({members}))
)
);
I really like the indirection here, how it moves the intelligence, especially the logic to conditionally load the members, out of the component and into the effect. The only difficulty is I can't think of an elegant/clean way to handle the loading flag on the state for this data. I really don't want to add a reducer for memberListInitialized that also has logic to figure out if I'm actually loading members. I can easily set loading to false in a reducer for membersLoaded, but when do I set loading to true?
Here's the state for this module...
export const initialState: MemberState = {
members: [],
loading: false,
loaded: false,
};