Search code examples
ngxs

Resetting Application State on Logout


I have an application that has state classes for a number of topic areas in the application. Say it is a chat app and the the topics are users, chat messages and chat rooms. The user is authenticated/authorized by logging in. From there after the state is depends on the user that is logged in. When the user logs out, the app needs to reset the state of all of the 'topics' to their default state.

Questions:

  1. What's the best way to organize these states? It seems like a good usage of substates, but the substate documentation talks about how to setup substates but doesn't show any examples of what it means for the states to be 'bound together'
  2. How do I reset all of the states? Is this a good usage of the reset API?

Solution

    1. Each feature module should define its own slice of state in a pair of files named feature-name.actions.ts and feature-name.state.ts, located inside the feature subdirectory (see the official style guide).

    2. As you said, each feature state can respond to actions defined in other states, and update its own state accordingly. Here's an example:


    src/app/auth/auth.state.ts:

    ...
    // Import our own actions, including the Logout action
    import { Logout, ... } from './auth.actions';
    
    
    export interface AuthStateModel {
      token?: string;
      currentUser?: User;
      permissions: string[];
    }
    
    const defaults: AuthStateModel = {
      token      : null,
      currentUser: null,
      permissions: [],
    };
    
    
    @State<AuthStateModel>({
      name: 'auth',
      defaults
    })
    export class AuthState {
      ...
      // Respond to the Logout action from our own state
      @Action(Logout)
      logout(context: StateContext<AuthStateModel>) {
        context.setState({ ...defaults });
      }
      ...
    }
    

    src/app/users/users.state.ts:

    ...
    // Import our own actions
    import { LoadAllUsers, ... } from './users.actions';
    
    // Import the Logout action from the Auth module
    import { Logout }       from '../auth/auth.actions';
    
    
    export interface UsersStateModel {
      users?: User[];
    }
    
    const defaults: UsersStateModel = {
      users: null,
    };
    
    
    @State<UsersStateModel>({
      name: 'users',
      defaults
    })
    export class UsersState {
      ...
      // An example of the usual case, responding to an action defined in
      // our own feature state
      @Action(LoadAllUsers)
      loadUsers(context: StateContext<UsersStateModel>, action: LoadAllUsers) {
        ...
      }
    
    
      // Respond to the Logout action from the Auth state and reset our state (note
      // that our context is still of type StateContext<UsersStateModel>, like the other
      // actions in this file
      @Action(Logout)
      logout(context: StateContext<UsersStateModel>) {
        context.setState({ ...defaults });
      }
      ...
    }
    

    Note that although AuthState.logout() and UsersState.logout() both respond to the Logout action (defined in the AuthState module), the AuthState.logout() function accepts a context of type StateContext<AuthStateModel>, because we want to call that context's setState() function to update the 'auth' feature state. However, the UsersState.logout() function accepts a context of type StateContext<UsersStateModel>, because we want to call that context's setState() function to reset the 'users' feature state.

    Each additional feature module can respond to the Logout action in the same way as UsersState did, and reset their own slice of the state.