web-dev-qa-db-fra.com

Comment réinitialiser tous les états de ngrx / store?

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
      })
    )
  ]);
20
Hongbo Miao

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(...))
    ],
    ...
14
cartant

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'])
});
33
David Bulté

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 }),
   ...
]
14
Limarenko Denis

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);
2
Helzgate