Reputation: 1216
My Objective: Update my service file with the 'NgRx' way of doing things.
I am making a GET request to fetch menu data from my service, as soon as that call occurs, I want it to set my 'menu' state in NgRx, so that I can access the menu data everywhere.
I'm not sure what the best way to approach this is.
My current code:
Menu.service.ts
constructor(private http: HttpClient, private store: Store<fromApp.AppState>) { }
public getMenu(): Observable<Restaurant> {
// not sure where to run this code:
// this.store.dispatch(new MenuActions.SetMenu(menu));
return this.http.get<Menu>('http://localhost:1234/api/menu');
}
Questions:
1.) Is it best practice to dispatch the menu item in my service?
2.) Should I use the 'pipe' operator after the call is made to dispatch the update?
3.) If I'm using NgRx, I feel like I don't need to subscribe to getMenu()
, since the state will be set in this file, and I can just access state where I'd normally subscribe to this service. Is using the service file here valid, or am I taking the wrong approach for ngrx? If this isn't correct, what is the alternative?
Thanks!
Upvotes: 2
Views: 2934
Reputation: 20092
Is it best practice to dispatch the menu item in my service?
You can but I wouldnt recommend because NGRX has effect for that. Effect stand for side effect to do some logic calculation.
Should I use the 'pipe' operator after the call is made to dispatch the update?
You should not.
If I'm using NgRx, I feel like I don't need to subscribe to getMenu(), since the state will be set in this file, and I can just access state where I'd normally subscribe to this service. Is using the service file here valid, or am I taking the wrong approach for ngrx? If this isn't correct, what is the alternative?
You should not. Instead subcribe like this in your component
Example
I have service like this
getPosts(): Observable<any> {
return this.http.get("https://jsonplaceholder.typicode.com/posts");
}
Then my effect to call the api
getPosts$ = createEffect(() =>
this.actions$.pipe(
ofType(PostActions.LoadPosts),
switchMap(_ => {
return this.postService
.getPosts()
.pipe(
map(
(posts: IPost[]) => PostActions.LoadPostsSuccess({ posts }),
catchError(errors => of(PostActions.LoadPostsFail(errors)))
)
);
})
)
);
So in my container component
public posts$: Observable<IPost[]>;
constructor(private store: Store<PostState>) {}
ngOnInit() {
this.store.dispatch(LoadPosts());
this.posts$ = this.store.pipe(select(selectAllPosts));
}
<div class="row">
<div class="col-3" *ngFor="let post of posts$ | async">
<div class="card card-container">
<div class="card-body">
<h5 class="card-title">{{ post.title }}</h5>
<p class="card-text">{{ post.body }}</p>
<a
class="btn btn-outline-primary"
[routerLink]="['/posts/',post.id]"
role="button"
>Go to detail</a
>
</div>
</div>
</div>
</div>
Of course you will need selector to get the data in your component
export const selectPostState = createFeatureSelector<PostState>(
POST_FEATURE.storekey
);
export const selectPostsEntities = createSelector(
selectPostState,
posts => posts.entities //object look up
);
export const selectAllPosts = createSelector(
selectPostsEntities,
posts => Object.keys(posts).map(key => posts[key]) // use *ngFor
);
Upvotes: 1