Reputation: 492
I already saw same quesion here but since I use ngrx9 I think there should be slighly different solution. My code and reducers in app modules look like this
.....
StoreModule.forRoot(
reducers,
{
metaReducers,
runtimeChecks: {
strictStateImmutability: true,
strictActionImmutability: true
}
}),
...
And my imported reducers are
export const reducers: ActionReducerMap<AppState> = {
[friendsReducer.friendsFeatureKey]: friendsReducer.reducer,
[authReducer.authFeatureKey]: authReducer.reducer,
...
};
export const metaReducers: MetaReducer<AppState>[] = !environment.production ? [] : [];
My LOGOUT
action is stored in auth.actions
.
So how should I include root reducer to reset all the states?
Upvotes: 1
Views: 2792
Reputation: 1079
The accepted answer is a suggestion that I see often on StackOverflow, and unfortunately it's something you should never ever do.
If you make your state potentially undefined you will run in to several problems:
Anything you connect to your store (usually just selectors), will be have to be written in a way that takes in to account potentially undefined values. This will get ugly real fast, and could potentially lead to hard to find errors if mistakes are made.
Javascript engines perform better if the objects that they manipulate are of the same "shape". This subject is complicated, but the basic idea is that if objects have the same shape, the compiler can optimize operations using an inline cache (here is a more detailed article on the subject: https://mrale.ph/blog/2015/01/11/whats-up-with-monomorphism.html). If you reset your state by just making it undefined, then the state object changes shape, and you lose some performance. In most applications, this probably won't have a noticeable impact, but it's something to be aware of.
You break one of the fundamental principles of the redux design pattern, which is that you should maintain a centralized state store with a consistent interface. One of the selling points of the redux design pattern is that if you follow it, you know that your application state will always have a consistent interface, and you don't ever have to worry about certain parts of state not being there, and the issues that could cause. That's why reducers are always created from an initial state object, and properties of state are created eagerly when their providers are loaded instead of being added to state on the fly. If you reset your state by setting it to undefined, you lose this guarantee, along with a big chunk of redux's value.
To clear a store, you need to dispatch an action that is reduced to a new initial state object. One of the great things about ngrx/redux is that actions are dispatched along a single stream. This means that reducers in one feature store (in your case 'friends') can listen for actions in another store (in your case 'auth'). So, in your friends.reducer.ts do something like:
import * as AuthActions from 'wherever/your/auth/actions/are';
// Replace this with actual interface
export interface FriendsState {
friends: string[];
}
// Replace this with actual object
export const initialFriendsState:FriendsState = {
friends: [],
}
export const reducer = createReducer(
initialFriendsState,
on(AuthActions.LOGOUT, (state: FriendsState) => ({...initialFriendsState})),
on(FriendsActions.GET_FRIENDS (state: FriendsState, {friends}) => ({...state, friends})
//...whatever other reducers you have in your friends store
);
Upvotes: 4
Reputation: 12036
just add metareducer to clear your state
export function clearOnLogoutMetaReducer(reducer) {
return function(state, action) {
if(action.type === logout.type) {
return reducer(undefined, action);
}
return reducer(state, action);
}
}
and add it to your metareducers array
Upvotes: 2