首页 > 解决方案 > NGXS:如何在 meta-reducer 中使用 Store 或 set State

问题描述

我需要从 meta-reducer 或插件中调度一个动作。将此提供程序添加到应用程序模块时出现以下错误:

   {
       provide: NGXS_PLUGINS,
       useFactory: myfunction,
       deps: [Store],
       multi: true
    }

无法实例化循环依赖!InternalStateOperations ("[ERROR ->]"):在 NgModule AppModule 中

无法实例化循环依赖!StateFactory ("[ERROR ->]"): 在 NgModule AppModule 中

正确的方法是什么?

元减速器是:

export function extendApplication(store: Store) {
  return function extendApplication(state, action, next) {
  if (state.user.loggedIn){

    if (getActionTypeFromInstance(action) !== LogoutUser.type) {

      here is where I want to set a timer and if no other actions
      occur before the timer expires I want to dispatch a logout action

      return next(state, action);
    }
  }else{
    return next(state, action);
  }}

该模块具有上述提供者。

标签: angularnativescriptngxs

解决方案


MetaReducers 可以通过函数或服务(类)来实现。

如果你通过一个函数来实现它,你可以这样做:

import { NgModule } from '@angular/core';
import { NGXS_PLUGINS } from '@ngxs/store';
import { getActionTypeFromInstance } from '@ngxs/store';

@NgModule({
  imports: [NgxsModule.forRoot([])],
  providers: [
    {
      provide: NGXS_PLUGINS,
      useValue: logoutPlugin,
      multi: true
    }
  ]
})
export class AppModule {}

export function logoutPlugin(state, action, next) {
  // Use the get action type helper to determine the type
  if (getActionTypeFromInstance(action) === Logout.type) {
    // if we are a logout type, lets erase all the state
    state = {};
  }

  // return the next function with the empty state
  return next(state, action);
}

仅通过更新传递给函数的state对象并将其传递回返回的next函数来改变状态。

您可以在插件中注入 Store,使用Injector和获取实例,但您不能在插件内调度动作,因为您将创建一个无限循环。

如果你想通过服务来实现它,你可以这样做:

import {
  NGXS_PLUGINS,
  NgxsModule,
  ActionType,
  NgxsNextPluginFn,
  NgxsPlugin
} from "@ngxs/store";
import { Injectable, Inject, Injector } from '@angular/core';

@NgModule({
  imports: [
    NgxsModule.forRoot([TestState]),
  ],
  providers: [
    {
      provide: NGXS_PLUGINS,
      useClass: TestInterceptor,
      multi: true
    }
  ]
})
export class AppModule {}

@Injectable()
export class TestInterceptor implements NgxsPlugin {

  constructor(
    private _injector: Injector
  ){
  }

  public handle(
    state,
    action: ActionType,
    next: NgxsNextPluginFn
  ): NgxsNextPluginFn {
    const matches: (action: ActionType) => boolean = actionMatcher(action);
    const isInitialAction: boolean = matches(InitState) || matches(UpdateState);  

    // you can validate the action executed matches the one you are hooking into
    // and update state accordingly

    // state represents full state obj, if you need to update a specific state, 
    // you need to use the `name` from the @State definition

    state = { test: ["state mutated in plugin"] };

    // get store instance via Injector 
    const store = this._injector.get<Store>(Store);

    return next(state, action);
  }
}


如果您想查看它,我还创建了stackblitz示例


推荐阅读