If item not in the store, dispatch an action to fetch it

Viewed 2300

I'm trying to figure out what is the best way to fetch an item if it's not in the store.

For instance, let say that I have a list of users and I want to fetch a specific user. If that user isn't in the store I want to fetch him from the DB.

Is this code below considered best practice or is there a better way doing so?

const searchedUserId = 'abcdefg'; 
this.selecedUser$ = this.store.select(state => {
   const selectedUserIndex = state.userList.findIndex(searchedUserId)
   if (selectedUserIndex === -1) {
     this.store.dispatch(new UsersActions.FetchUsers(searchedUserId));  
   } else {
     return state.userList[selectedUserIndex]
   }
})
5 Answers
const searchedUserId = 'abcdefg';
this.selecedUser$ = this.store.select('userList').pipe(
  map(userList=>{const result = userList.findIndex(item=>item.id===searchedUserId);
  return result === -1 ? {} : result;
  }),
  tap(userList=>{
    if( !userList.hasOwnProperty('id') ) this.store.dispatch(new UsersActions.FetchUsers(searchedUserId));
  })
);

tap will not change the observable and when the dispatched action will change the state, the observable will be updated.

Use an selector instead of the select statement and be aware about the situation the action will not found the key.

if it's not in the store nor fetched then your application doesn't need this piece of information. usually this kind of logic will go into guards, initializers, resolvers or any other logical method to fetch this kind of data.

If i'll look at the flow you described then in order to reach the user page you are talking about I'll have to click on something to navigate to that page or even just collapse a card or something similar.

At this point after the event happened then your application have several different ways to do that, either send a request/dispatch action which fetch the data, either with a guard/resolver.

Subscribing inside the store itself to the store data and fetching more data based on the store state is bad practice and will lead to infinite loops, issues with debugging and figuring out who fires what.

I came to this as I had a similar situation where I don't want to make the http request if the data is already present in the store.

As far as I see it the following would be acceptable and still keep the separation of concerns with regards to selectors / effects / store etc.

  1. Create selector to return user from store.
  2. Dispatch your fetch action in the component's init.
  3. Inside the effect use the selector to query the store. If the selector returns null then request the data from the back-end.
  4. Return the user in a fetchSucceeded action
  5. Update store in reducer on fetchSucceeded

How to Use State Inside of an Effect Component With ngrx

Related