Search code examples
angularngrx-store

Same store on multiple component


in my app I have user.component and college.component. In user.component with store i get users list

this.store.dispatch(new LoadUsers());
this.users$ = this.store.select(UserSelector.getAllUsers)
this.users$.subscribe(...)

And on college.component I also need this user from store, and I call same dispatch

this.store.dispatch(new LoadUsers());
this.users$ = this.store.select(UserSelector.getAllUsers)
this.users$.subscribe(...)

I call the same this.store.dispatch(new LoadUsers()); because, if I on first page load open college page, I don't have users in store, and I need to call them.

If I first open users.component I get users but when I after going on college page I get error

Cannot read property 'data' of undefined for users.

What is the best way in this case to handle store like this?

Check if data exist in store and call dispatch or make same action/reducer/effect for loadUsers() for every component??

Thnx


Solution

  • If your user data changes a lot, it's ok to reload. If your user data is quite static, which it normally would be, it's not wise to make that call multiple times because it just makes your app slower for no reason.

    To tackle the single loading, there's two ways of doing it. you should hold a loaded parameter on your entity and then on load success put that loaded value to true in the reducer.

    You can now subscribe to that loaded value, if it's false dispatch the load, if it's true don't dispatch the call. This route keeps the effects simpler but your containers will have longer/uglier code.

    constructor(private store: Store<fromAuth.State & fromData.State>){
      this.users$ = this.store.select(UserSelector.getAllUsers);
    }
    
    
    ngOnInit() {
      this.store.select(UserSelector.getUsersLoaded).subscribe(value => 
        if (!value) this.store.dispatch(new LoadUsers());
      );
    }
    

    A smoother way is to keep your code as is and do this check in the effect. (replied to me by Duncan Hunter on Pluralsights course on ngrx) (ref. to ngrx course on pluralsight)

    1. Component loads and subscribe to the store variable where the data might or will be.
    2. Dispatch the action on ngOnInit to load the data.
    3. In an effect check if store has the data and maybe if it is older than a certain time. I try my best to only check the store in effect as little as possible as it makes them more complicated but in real projects I often have 6-12 effects like this.
    4. If no data or stale call http to load but if it is already loaded I then dispatch an action like {type: 'entityXLoadedFromStore'}; Which does not do anything but add a log message into the system to be able to see it was loaded from the store.

    This route keeps your code cleaner in the containers, but makes the effects complex.

    Both routes are viable, you can choose which you prefer.

    I'd like to reference to the fantastic demo app given by the NGRX team as well, which is a great source of inspiration for ngrx methods. (However they don't address your question in there).