简体   繁体   中英

Angular 8 set state from http with NgRx

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!

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
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM