Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check data in Angular Store before calling API with NGRX using observables

I am using Angular with NGRX effects and I am new to the world of observables. I want to check that if data exists in my store, then the API should not be called, and data should be pulled from the store. I managed to find that I can use withLatestFrom() which can check the latest value in the store. The next part is confusing me and I cant get it to work. My current code is below:

 @Effect() getSomeContent$ = this.actions$
    .ofType(GET_SOME_CONTENT)
    .withLatestFrom(this.store$.select('store-section'))
    .map(([action, store]) => {
        const content = {};
        if (store.someContent.length > 0) {
           return new GetCategoryContentSuccessAction({ categoryContent: categories });
        }
        return Observable.from(action.payload);
    })
    .switchMap(payload => this.APIcall(payload)
        .then(data => {
            const content = {};
            data.items.map((item) => {
                const slug = data.slug;
                content[slug] = {
                    info: datasomeData
                };
            });
            return new GetSomeContentSuccessAction({ categoryContent: categories });
        })
        .catch((err) => {
            return new GetFailureAction({ error: {} });
        })
    );

I want to use some kind of if or else statement to check the store. If data exists i want to send an empty object back for the reducer I have to handle. If it doesn't I want to call the API and send that data back. I don't know if the observable can be branched in other words so this can be done?

Is there a better way that this could have been achieved? Possibly by creating another action to deal with the API separately. I would like to learn what the best practice is going forward. Any help would be greatly appreciated.

like image 931
mineshmshah Avatar asked Jun 05 '18 17:06

mineshmshah


1 Answers

I was just working on a solution to this exact issue so I thought I would put my 2 cents here just in case anyone else might find it helpful.

There is a great article Stop Using NGRX Effects For That. Which talks about how complex it is to try and cram this inside of the ngrx effects chain.

Instead they recommend using a service, which I have been using and love. A simple version might look like this.

Service: 

public posts$ = this.store.select(postSelectors.selectAll)
    .pipe(
        tap(posts => {
            if (!posts.length) {
                this.store.dispatch(new postActions.LoadMany());
            }
        }),
        filter(posts => posts !== null)
    );

Here we basically just try and select the piece of state that we want and if its not there then dispatch an action that will trigger an effect to get it from the api and push it into the store.

Component: 

this.posts$ = this.postService.posts$;

Then in your component you can just subscribe to the observable from your service and not care if it's in the store yet or not. Then you can either subscribe to that in your component to get the value or push it to the template with the async pipe.

This works really well for simple stuff but I'm still working on more complicated RXJS chains for when you have to get data that depends on other data to exist first. But, that's just a limitation of my abilities on writing RXJS functions.

like image 127
DerrickF Avatar answered Oct 21 '22 00:10

DerrickF