Store: What is best way to clear entire store on logout action?

Created on 20 Jul 2018  路  6Comments  路  Source: ngxs/store

I am having multiple sub store lazy loaded with modules. I am keeping main store in core module which has access to all Auth Actions. When the user's logout (kicks logout action) then I want to clear all the sub-stores which were lazy loaded earlier.

What is the best recommended way to do?

Shall I subscribe core module's Logout action in all sub-stores and clear individual sub-store on logout action? The problem with the approach I feel that I need to careful every time, I am creating a new sub store, as I need to make sure to clear the store and need to subscribe to Logout action which is part of core module. I kind of having feeling that it will make my application tightly bound.

OR

Is there any other better way?

Most helpful comment

Nice, Meta Reducer is much better. I was looking for the same. I tried and it is working perfectly fine. Thanks.

All 6 comments

In continuation to above thread, I am injecting store and actions within my State Class itself. Is the right way?

My Current code as follows:

user.action.ts

import { AppStateModel } from '@app/store/app.state';

export interface UserStateModel extends AppStateModel {
    id: string;
    username: string;
    email: string;
    name?: string;
    address?: any;
    phone?: string;
    website?: string;
    company?: any;
}

export class GetProfile {
    static readonly type = '[User] Get Profile';
    constructor(public payload: string) { }
}

export class ClearUser {
    static readonly type = '[User] Clear User on Logout';
}

and user.state.ts

import { State, Action, StateContext, Selector, Actions, ofActionDispatched, Store } from "@ngxs/store";

import { UserStateModel, GetProfile, ClearUser } from '@app/core/user/user.action';
import { ProfileService } from "@app/core/user/profile.service";
import { tap } from "rxjs/operators";
import { Logout } from "@app/core/auth/store/auth.action";


@State<UserStateModel>({
    name: 'user',
})

export class UserState {

    constructor(private profileService: ProfileService, private actions: Actions, private store: Store) {

        this.actions.pipe(ofActionDispatched(Logout)).subscribe(() => {
            this.store.dispatch(new ClearUser());
        })

    }

    @Selector()
    static observeUser(state: UserStateModel) {
        return (key) => {
            return key ? state[key] : state;
        }
    }

    @Action(ClearUser)
    ClearUser(ctx: StateContext<UserStateModel>) {
        return ctx.setState({ username: undefined, id: undefined, email: undefined });
    }

    @Action(GetProfile)
    GetProfile(ctx: StateContext<UserStateModel>, { payload }: GetProfile) {
        const state = ctx.getState();
        return this.profileService.getProfile(payload)
            .pipe(
                tap((result: { profile: UserStateModel }) => {
                    const profileData = result ? result[0] : {};

                    ctx.setState({
                        ...state,
                        username: profileData.username,
                        id: profileData.id,
                        phone: profileData.phone,
                        address: profileData.address,
                        company: profileData.company,
                        email: profileData.email,
                        name: profileData.name,
                        website: profileData.website
                    })
                })
            );
    }

}

If you want to clear the whole state, you need to use meta reducer.

And if you want to clear only the user state, you can implement just like I wrote in the PR #501 .

Nice, Meta Reducer is much better. I was looking for the same. I tried and it is working perfectly fine. Thanks.

link above gives 404, updated link is:
https://ngxs.gitbook.io/ngxs/advanced/meta-reducer

my HUGE thanks!

Honestly I don't like the name meta-reducer it is not reducer but interceptor or middleware. I think we are teaching bad practices to people who are new to redux. It might be harder to understand what meta-reducer actually is for people who don't know how redux works under the hood. Anyway for future reference if you want to clear state and redirect user (or getState or dispatch some actions) here is an example of how to do that. 馃檪

NOTE: Keep in mind that {} resets the app state. You have to restore initial values if you have any so technically the provided answer is not correct.

import { ActionType, getActionTypeFromInstance, NgxsNextPluginFn, NgxsPlugin, Store } from '@ngxs/store';
import { Injectable, Injector } from '@angular/core';
import { RequestLogout } from './auth.actions';
import { Navigate } from '@ngxs/router-plugin';
import { StateResetAll } from 'ngxs-reset-plugin';

@Injectable()
export class LogoutMiddleware implements NgxsPlugin {

  constructor(
    private injector: Injector,
  ) {
  }

  public handle(
    state: any,
    action: ActionType,
    next: NgxsNextPluginFn,
  ): NgxsNextPluginFn {
    if (getActionTypeFromInstance(action) === RequestLogout.type) {
      const store = this.injector.get<Store>(Store);
      store.dispatch(new Navigate(['/login']));
      store.dispatch(new StateResetAll());
    }

    return next(state, action);
  }
}
Was this page helpful?
0 / 5 - 0 ratings