25

我正在使用 Angular 2 和ngrx/store。我想在用户调度时重置整个商店状态USER_LOGOUT

我阅读了 Dan Abramov 关于如何重置 Redux 商店状态的回答?,但是我没有弄清楚如何rootReducer正确编写以及使用ngrx / store时将其放在哪里。

或者有没有其他方法可以在ngrx/store 中处理这个问题?

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

4 回答 4

44

在 ngrx/store 4.x 中,这可以通过Meta-reducers来完成。据我了解,所有操作都经过元缩减器,然后才移交给特征缩减器。这使我们有机会首先更改/重置状态。

这是一个例子。

这是我的 metareducer 函数:如果动作是 LOGOUT 类型,则重新初始化状态。

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

下面你会看到 metareducer 是如何与 feature reducer 一起配置的。如果有超过 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'])
});
于 2017-07-26T10:16:44.643 回答
15

此答案特定于 ngrx 版本 2。该问题有另一个更新的答案,解释了如何使用 ngrx 版本 4 完成相同的操作。


compose构建 ngrx根减速器

传递给的参数compose是返回 reducer 的函数 - 由 reducer 组成,它们本身作为参数传递。您可以像这样编写商店的重置:

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(...))
    ],
    ...
于 2016-09-05T03:38:37.370 回答
15

使用 @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 }),
   ...
]
于 2017-09-20T00:10:53.357 回答
3

这不是一个真正的答案,但评论不会让我正确格式化它。补充一下carant所说的,如果您要这样设置类型:

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);
于 2017-02-18T17:26:25.060 回答