ngrx Load data from server only if the store is empty

谁说胖子不能爱 提交于 2019-12-01 03:11:32

There are different ways of doing this. First of all you can keep a hasLoaded: boolean property in de state. Then you can check this before you make the service get call.

ngOnInit() {
  this.store.select(getHasLoaded)
    .take(1)
    .subscribe(hasLoaded => {
      if (!hasLoaded) this.store.dispatch(new countries.Load()); 
    }
}

Another option is to let your @Effect check the hasLoaded property:

@Effect()
  loadCollection$: Observable<Action> = this.actions$
    .ofType(countries.LOAD)
    .withLatestFrom(this.store.select(getHasLoaded)
    .filter(([ action, hasLoaded ]) => !hasLoaded) // only continue if hasLoaded is false 
    .switchMap(() =>
      this.countriesService
        .getCountries()
        .map((countriesList: Country[]) => {
          return new countries.LoadSuccess(countriesList);
        })
    .catch(error => of(new countries.LoadFail(error)))
);

For this to work you need to provide the store in your Effects constructor.

Yossely Mendoza Meneses

TL;DR

Use take(1) operator in the effect

Don't forget the error handling using catchError and return EMPTY, otherwise when an error occurs, that error will be returned always (timeout, auth error, offline...)


I had exactly the same case as you, what I did was adding in the effects the rxjs operator take to fetch the countries only the first time the LoadCountries action was dispatched.

@Effect()
  loadCountries$: Observable<CoreActions> = this.actions$.pipe(
    ofType(CoreActionTypes.LoadCountries),
    mergeMap(() =>
      this.countriesService.getAllCountries().pipe(
        map(c => new LoadCountriesSuccess(c)),
        catchError(() => {
          this.store.dispatch(new LoadCountriesFailed());
          return EMPTY;
        })
      )
    ),
    take(1)
  );

Returning EMPTY inside catchError will complete the observable without passing through the take(1)

You can select the countries from the store within effects, if they are represented in the store we ignore the action, if not we fetch the countries.

@Effect()
getOrder = this.actions.pipe(
  ofType<GetOrder>(ActionTypes.GetOrder),
  withLatestFrom(this.store.pipe(select(getOrders))),
  filter(([{payload}, orders]) => !!orders[payload.orderId])
  mergeMap([{payload}] => {
    ...
  })
)

For more info see Start using ngrx/effects for this.

My answer is a variation from Hetty de Vries answer's. If you simply want to retrieve the contents of the store without touching the effects you could do something similar to this:

this.store.select(state => state.producer.id).forEach( id => {
...
}

supposing that your store contains a producer object with an attribute id.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!