Search code examples
angularreduxngrx

Ngrx after reseting the store, component dispatching an action


I have implemented the Store for my App. After logout I want to reset store. But there is a problem.

Let's assume I have the following State:

subjects: {
    subjectsLoaded: true
}

In component I'm subscribe to the store like that:

 this.store.pipe(
        select(areSubjectsLoaded),
         tap((subjectsLoaded) => {
             if (!subjectsLoaded) {
                 this.store.dispatch(loadSubjects());
                 console.log('Dispatching Subjects because they are not Loaded');
             }
         }),
         filter(subjectsLoaded => subjectsLoaded),
         takeUntil(this.unsubscribe$)
     ).subscribe();

After logout and reseting the store, it will looks like:

 subjects: {
    subjectsLoaded: false
}

Since I am subscribed to changes in the component, an action dispatch will be made. But I don't know how to prevent this. I'm also using takeUntil in order not to receive data after the destroy of the component

There is a small demo:

enter image description here

For clear the store I'm using metaReducers:

export const metaReducers: MetaReducer<AppState>[] = [clearState];

export function clearState(reducer: ActionReducer<AppState>): ActionReducer<AppState> {
  return (state: AppState, action: Action): AppState => {
    if (action.type === '[Toolbar] User Logout') {
      console.log('Clear state: ',state);
      state = undefined;
    }
    return reducer(state, action);
  };
}

Solution

  • I think you'll have to use something else than undefined, because, as you've seen, you can no longer distinguish 'state has not been initialized' and 'state must reset'.

    You could use a symbol to differentiate these states.

    export const RESET_STATE = Symbol('reset state');
    
    // your meta-reducer
    state = RESET_STATE;
    
    return state;
    

    Now you could recognize them this way:

    this.store.pipe(
      filter(state => state !== RESET_STATE),
      select(areSubjectsLoaded),
      /* ... */
    )
    

    If you don't want to repeat yourself, you could create a selector out of that logic and use it in your other selectors as well.