J'utilise Angular 2 avec ngrx/store . Je veux réinitialiser tous les états du magasin lorsque l'utilisateur envoie USER_LOGOUT
.
J'ai lu la réponse de Dan Abramov de Comment réinitialiser l'état d'un magasin Redux? , mais je n'ai pas compris comment écrire rootReducer
correctement et où le mettre lors de l'utilisation de ngrx /boutique.
Ou existe-t-il un autre moyen de gérer cela dans ngrx/store?
bootstrap(App, [
provideStore(
compose(
storeFreeze,
storeLogger(),
combineReducers
)({
router: routerReducer,
foo: fooReducer,
bar: barReducer
})
)
]);
Cette réponse est spécifique à ngrx version 2. La question a ne autre réponse plus récente qui explique comment faire la même chose avec ngrx version 4.
compose
construit le réducteur racine ngrx .
Les arguments passés à compose
sont des fonctions qui renvoient un réducteur - composées du réducteur, elles sont elles-mêmes passées en argument. Vous pouvez composer la réinitialisation de votre magasin comme ceci:
import { compose } from "@ngrx/core/compose";
...
bootstrap(App, [
provideStore(
compose(
storeFreeze,
storeLogger(),
(reducer: Function) => {
return function(state, action) {
if (action.type === 'USER_LOGOUT') {
state = undefined;
}
return reducer(state, action);
};
},
combineReducers
)({
router: routerReducer,
foo: fooReducer,
bar: barReducer
})
)
]);
Notez que cela réinitialisera tous les états du magasin - y compris le router
. Si ce n'est pas ce que vous voulez, vous pouvez modifier l'exemple.
Avec l'introduction de NgModule
, le bootstrap a changé, mais vous passez toujours le réducteur composé à provideStore
:
import { compose } from "@ngrx/core/compose";
import { StoreModule } from "@ngrx/store";
@NgModule({
...
imports: [
...
StoreModule.provideStore(compose(...))
],
...
Dans ngrx/store 4.x, cela peut être accompli avec metareducers . Si je comprends bien, toutes les actions passent par les métaréducteurs avant d'être remises aux réducteurs de fonctionnalités. Cela nous donne la possibilité de changer/réinitialiser l'état en premier.
Voici un exemple.
C'est ma fonction de métaréducteur: si l'action est de type LOGOUT, l'état est réinitialisé.
function logout(reducer) {
return function (state, action) {
return reducer(action.type === LOGOUT ? undefined : state, action);
}
}
Ci-dessous, vous voyez comment le métaréducteur est configuré avec les réducteurs de fonctionnalités. S'il y a plus d'un métaréducteur, ils sont évalués de droite à gauche
StoreModule.forRoot({rooms: roomReducer, user: userReducer}, {metaReducers: [logout]})
Enfin, j'ai également un @effect où je navigue vers la page de connexion
@Effect({dispatch: false}) logout: Observable<Action> =
this.actions$.ofType(LOGOUT)
.do(() => {
// ... some more stuff here ...
this.router.navigate(['/login page'])
});
Avec @ ngrx/store ":" ^ 4.0.3 "c'est légèrement différent car il y a de petits changements, donc mon" état clair "ressemble à ceci
import { ActionReducerMap } from '@ngrx/store';
import { ActionReducer, MetaReducer } from '@ngrx/store';
export const rootReducer: ActionReducerMap<StoreStates> = {
points: pointsReducer,
...
};
export function clearState(reducer: ActionReducer<StoreStates>): ActionReducer<StoreStates> {
return function(state: StoreStates, action: Action): StoreStates {
if (action.type === 'CLEAR_STATE') {
state = undefined;
}
return reducer(state, action);
};
}
export const metaReducers: MetaReducer<StoreStates>[] = [clearState];
et
import { StoreModule } from '@ngrx/store';
import { metaReducers, rootReducer } from '../root.reducer';
export const imports: any = [
StoreModule.forRoot(rootReducer, { metaReducers }),
...
]
Ce n'est pas vraiment une réponse mais les commentaires ne me permettront pas de le formater correctement. Pour ajouter à ce que Cartant a dit, si vous configurez vos types comme ceci:
export const ActionTypes = {
LOGOUT: type('[Environment] Logout of portal'),
....
}
C'est la longue description que vous devez utiliser. De plus, si vous nommez votre réducteur racine rootReducer
au lieu de simplement reducer
, vous changeriez cela également. Voici un exemple modifié:
(J'ai laissé cette fonction dans mon réducteur de racine)
const developmentReducer: ActionReducer<State> = compose(...DEV_REDUCERS,
(rootReducer: Function) => {
return function(state, action) {
if (action.type === '[Environment] Logout of portal') {
state = undefined;
}
return rootReducer(state, action);
};
}, combineReducers)(reducers);