I have a static set of data, a list of countries, that are used on some components. This data is loaded upon the ngOnInit()
of these components but I'd like to load them only if it's the very first time that I request the data (the store is empty). Every subsequent times I load the component I'd like to simply use the data from the store without "refreshing" it.
How is this achievable using ngrx?
I'm using Effects. This is how my code looks like:
The component:
export class EditPageComponent implements OnInit {
countries$: Observable<Country[]>
constructor(private store: Store<fromContacts.State>) {
this.countries$ = store.select(fromContacts.getCountriesEntities);
}
ngOnInit() {
this.store.dispatch(new countries.Load());
}
The Effect:
@Effect()
loadCollection$: Observable<Action> = this.actions$
.ofType(countries.LOAD)
.switchMap(() =>
this.countriesService
.getCountries()
.map((countriesList: Country[]) => {
return new countries.LoadSuccess(countriesList);
})
.catch(error => of(new countries.LoadFail(error)))
);
And the reducer:
case countries.LOAD_SUCCESS: {
const countriesList: Country[] = action.payload;
const reducedCountries: { [id: string]: Country } = countriesList.reduce((countrs: { [id: string]: Country }, countr: Country) => {
return Object.assign(countrs, {
[countr.code]: countr
});
}, {});
Thanks, Gab
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:supposing that your store contains a
producer
object with an attributeid
.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.
For more info see Start using ngrx/effects for this.
There are different ways of doing this. First of all you can keep a
hasLoaded: boolean
property in the state. Then you can check this before you make the service get call.Another option is to let your @Effect check the hasLoaded property:
For this to work you need to provide the store in your Effects constructor.
TL;DR
Use
take(1)
operator in the effectI 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 theLoadCountries
action was dispatched.Returning
EMPTY
insidecatchError
will complete the observable without passing through thetake(1)