Angular NGXS:如何在meta reducer中使用存储或设置状态

Angular NGXS:如何在meta reducer中使用存储或设置状态,angular,nativescript,ngxs,Angular,Nativescript,Ngxs,我需要从meta reducer或插件中分派一个操作。将此提供商添加到应用程序模块时,我遇到以下错误: { provide: NGXS_PLUGINS, useFactory: myfunction, deps: [Store], multi: true } 无法实例化循环依赖项!InternalStateOperations(“[ERROR ->]“”:在NgModule AppModule中 无法实例化循环依赖项!状态工

我需要从meta reducer或插件中分派一个操作。将此提供商添加到应用程序模块时,我遇到以下错误:

   {
       provide: NGXS_PLUGINS,
       useFactory: myfunction,
       deps: [Store],
       multi: true
    }
无法实例化循环依赖项!InternalStateOperations(“[ERROR ->]“”:在NgModule AppModule中

无法实例化循环依赖项!状态工厂(“[ERROR->]”):位于 NgModule应用模块

正确的方法是什么

meta-reducer是:

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

该模块具有上述提供程序。

可以通过函数或服务(类)实现MetaReducer

如果通过函数实现,可以执行以下操作:

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

只需更新传递到函数中的
状态
对象并将其传递回返回的
下一个
函数,状态就会发生变化

您可以使用
Injector
在插件中注入存储并获取实例,但是您不能在插件中分派actiom,因为您将创建一个无限循环

如果您想通过服务实现它,可以执行以下操作:

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


导入{
NGXS_插件,
NGXS模块,
动作类型,
NgxsNextPluginFn,
NgxsPlugin
}来自“@ngxs/store”;
从“@angular/core”导入{Injectable,injection,Injector};
@NGD模块({
进口:[
NgxsModule.forRoot([TestState]),
],
供应商:[
{
提供:NGXS_插件,
使用类别:睾丸接收器,
多:真的
}
]
})
导出类AppModule{}
@可注射()
导出类TestInterceptor实现NgxsPlugin{
建造师(
专用注射器:注射器
){
}
公共处理(
国家,,
action:ActionType,
下一个:NgxsNextPluginFn
):NgxsNextPluginFn{
常量匹配:(action:ActionType)=>boolean=actionMatcher(action);
常量isInitialAction:布尔=匹配(InitState)| |匹配(UpdateState);
//您可以验证执行的操作是否与您要挂接的操作匹配
//并相应地更新状态
//状态表示完全状态obj,如果需要更新特定状态,
//您需要使用@State定义中的'name'
state={test:[“插件中的状态突变”]};
//通过注入器获取存储实例
const store=this.\u injector.get(store);
返回下一步(状态、动作);
}
}

我还创建了一个示例,如果您想查看它的话

MetaReducer可以通过函数或服务(类)实现

如果通过函数实现,可以执行以下操作:

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

只需更新传递到函数中的
状态
对象并将其传递回返回的
下一个
函数,状态就会发生变化

您可以使用
Injector
在插件中注入存储并获取实例,但是您不能在插件中分派actiom,因为您将创建一个无限循环

如果您想通过服务实现它,可以执行以下操作:

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


导入{
NGXS_插件,
NGXS模块,
动作类型,
NgxsNextPluginFn,
NgxsPlugin
}来自“@ngxs/store”;
从“@angular/core”导入{Injectable,injection,Injector};
@NGD模块({
进口:[
NgxsModule.forRoot([TestState]),
],
供应商:[
{
提供:NGXS_插件,
使用类别:睾丸接收器,
多:真的
}
]
})
导出类AppModule{}
@可注射()
导出类TestInterceptor实现NgxsPlugin{
建造师(
专用注射器:注射器
){
}
公共处理(
国家,,
action:ActionType,
下一个:NgxsNextPluginFn
):NgxsNextPluginFn{
常量匹配:(action:ActionType)=>boolean=actionMatcher(action);
常量isInitialAction:布尔=匹配(InitState)| |匹配(UpdateState);
//您可以验证执行的操作是否与您要挂接的操作匹配
//并相应地更新状态
//状态表示完全状态obj,如果需要更新特定状态,
//您需要使用@State定义中的'name'
state={test:[“插件中的状态突变”]};
//通过注入器获取存储实例
const store=this.\u injector.get(store);
返回下一步(状态、动作);
}
}

我还创建了一个示例,如果您想查看它,请编辑:

实际上,当您可以使用已经有中间件的插件时,使用中间件是没有意义的。这样,我们所要做的就是创造行动:

@Action(RequestLogout)
async requestLogout(context: StateContext<IAuthStateModel>) {
  context.dispatch(new Navigate(['/login']));
  context.dispatch(new StateResetAll());
}
然后在您的应用程序模块中,您必须声明LogoutMiddleware(fun-fact meta reducer只是redux中间件的别致名称)并导入NgxsResetPluginModule

providers: [
    {
      provide: NGXS_PLUGINS,
      useClass: LogoutMiddleware,
      multi: true,
    },
    ...
  ],
  imports: [
    NgxsResetPluginModule.forRoot(),
    ...
  ],

编辑:实际上,当您可以使用已经有中间件的插件时,使用中间件是没有意义的。这样,我们所要做的就是创造行动:

@Action(RequestLogout)
async requestLogout(context: StateContext<IAuthStateModel>) {
  context.dispatch(new Navigate(['/login']));
  context.dispatch(new StateResetAll());
}
然后在您的应用程序模块中,您必须声明LogoutMiddleware(fun-fact meta reducer只是redux中间件的别致名称)并导入NgxsResetPluginModule

providers: [
    {
      provide: NGXS_PLUGINS,
      useClass: LogoutMiddleware,
      multi: true,
    },
    ...
  ],
  imports: [
    NgxsResetPluginModule.forRoot(),
    ...
  ],

您将在工厂函数中收到全局状态。在您的代码片段中,存储来自何处?它位于module.ts中的import语句中:import{NgxsModule,Store,NGXS_PLUGINS}from'@NGXS/Store'@我更新了代码。现在我可以看到,我已经两次引用了这个存储——一次在模块提供程序中,另一次在extendApplication函数中。在meta reducer中获取对存储的引用的正确方法是什么?您是否尝试将其作为插件实现,以便能够将存储注入构造函数?我也这样做了,但结果相同。您将在工厂函数中收到全局状态。在您的代码片段中,存储来自何处?它位于module.ts中的import语句中:import{NgxsModule,Store,NGXS_PLUGINS}from'@NGXS/Store'@我更新了代码。现在我可以看到,我已经两次引用了这个存储——一次在模块提供程序中,另一次在extendApplication函数中。在meta reducer中获取对存储的引用的正确方法是什么?您是否尝试将其实现为插件,以便能够在