Как сбросить все состояния ngrx / store?

Я использую Angular 2 с ngrx / store. Я хочу сбросить все состояния магазина, когда пользователь dispatch USER_LOGOUT.

Я прочитал ответ Дана Абрамова как сбросить состояние магазина Redux?, но я не понял, как писать rootReducer правильно и куда положить его при использовании ngrx / store.

или есть ли другой способ справиться с этим в ngrx / store?

bootstrap(App, [
    provideStore(
      compose(
        storeFreeze,
        storeLogger(),
        combineReducers
      )({
        router: routerReducer,
        foo: fooReducer,
        bar: barReducer
      })
    )
  ]);

4 ответов


этот ответ специфичен для ngrx версии 2. Вопрос другой, более свежий ответ это объясняет, как то же самое можно сделать с ngrx версии 4.


compose строит ngrx корень редуктор.

аргументы, переданные compose являются функциями, которые возвращают редуктор, составленный из редуктора, они сами передаются в качестве аргумента. Вы можете составить сброс вашего магазина, как это:

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

обратите внимание, что это сбросит все состояние магазина, включая router. Если это не то, что вы хотите, вы можете настроить пример.

введение NgModule загрузка изменилась, но вы все равно передаете составленный редуктор в provideStore:

import { compose } from "@ngrx/core/compose";
import { StoreModule } from "@ngrx/store";

@NgModule({
    ...
    imports: [
        ...
        StoreModule.provideStore(compose(...))
    ],
    ...

В ngrx / store 4.x, это можно сделать с помощью metareducers. Насколько я понимаю, все действия проходят через метаредукторы, прежде чем их передадут редукторам функций. Это дает нам возможность сначала изменить / сбросить состояние.

вот пример.

Это моя функция metareducer: если действие имеет тип LOGOUT, состояние повторно инициализируется.

function logout(reducer) {
  return function (state, action) {
    return reducer(action.type === LOGOUT ? undefined : state, action);
  }
}

ниже вы видите, как metareducer настроено вместе с редукторами функций. Если существует более 1 метаредуктора, то они оцениваются справа налево

StoreModule.forRoot({rooms: roomReducer, user: userReducer}, {metaReducers: [logout]})

наконец, у меня также есть @effect, где я перехожу на страницу входа

@Effect({dispatch: false}) logout: Observable<Action> = 
this.actions$.ofType(LOGOUT)
  .do(() => {
    // ... some more stuff here ...
    this.router.navigate(['/login page'])
});

С @ngrx / store": "^4.0.3 "это немного отличается, потому что есть небольшие изменения, поэтому мое "ясное состояние" выглядит так

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];

и

import { StoreModule } from '@ngrx/store';
import { metaReducers, rootReducer } from '../root.reducer';

export const imports: any = [
   StoreModule.forRoot(rootReducer, { metaReducers }),
   ...
]

это не совсем ответ, но комментарии не позволяют мне его правильно отформатировать. Чтобы добавить к тому, что сказал картант, если вы настраиваете свои типы следующим образом:

export const ActionTypes = {
  LOGOUT:  type('[Environment] Logout of portal'),
  ....
}

это длинное описание, которое вы должны использовать. Также, если вы назовете свой корневой редуктор rootReducer вместо reducer тогда вы бы изменили и это. Ниже приведен отредактированный пример:

(Я оставил эту функцию в своем корневом редукторе)

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