【问题标题】:How to reset all states of ngrx/store?如何重置ngrx/store的所有状态?
【发布时间】:2017-01-12 09:26:01
【问题描述】:

我正在使用带有ngrx/store 的Angular 2。我想在用户发送 USER_LOGOUT 时重置整个商店状态。

我阅读了 Dan Abramov 对 How to reset the state of a Redux store? 的回答,但我不知道如何正确编写 rootReducer 以及在使用 ngrx/store 时将其放在何处。

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

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

【问题讨论】:

    标签: angular typescript ngrx


    【解决方案1】:

    在 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。如果 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'])
    });
    

    【讨论】:

    • 这应该是公认的答案,因为现在 4.x 有一些变化。
    • 这对于 Angular 8 和 Ngrx-8 仍然完全有效。
    【解决方案2】:

    此答案特定于 ngrx 版本 2。问题有 another, more recent answer,它解释了如何使用 ngrx 版本 4 完成相同的操作。


    compose 构建 ngrx root reducer

    传递给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 的引入,引导发生了变化,但您仍然将组合的reducer 传递给provideStore

    import { compose } from "@ngrx/core/compose";
    import { StoreModule } from "@ngrx/store";
    
    @NgModule({
        ...
        imports: [
            ...
            StoreModule.provideStore(compose(...))
        ],
        ...
    

    【讨论】:

    • 如何在当前版本的ngrx中做到这一点?
    • @Daskus 你将组合reducer 传递给StoreModule.provideStore。查看更新后的答案。
    • @cartant 如何使用forRootforFeature 在最新的ngrx 版本上执行此操作?我在 angularindepth.com 上关注你,我希望能有一篇关于此的文章。
    • @AndreaM16 请参阅下面 David Bulté 的回答。
    【解决方案3】:

    与@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 }),
       ...
    ]
    

    【讨论】:

    • 当应用程序被组织成模块(延迟加载)并且每个模块都有自己的功能状态时,这将如何工作?
    • 它也适用于延迟加载,我的意思是我的所有功能模块都延迟加载,但服务和商店位于我放入应用程序模块的共享模块中
    • 顺便说一句,我的 CLEAR_STATE 操作是 LOGOUT ACTION)
    【解决方案4】:

    这不是一个真正的答案,但 cmets 不会让我正确格式化它。补充一下 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);
    

    【讨论】:

    • 你如何使用 productionReducer 做到这一点?
    猜你喜欢
    • 2018-01-17
    • 2019-06-07
    • 2017-03-02
    • 1970-01-01
    • 2022-07-17
    • 2019-07-24
    • 1970-01-01
    • 2017-08-30
    • 1970-01-01
    相关资源
    最近更新 更多