NGXS:如何在 meta-reducer 中使用 Store 或 set State
NGXS: How to use Store or set State in meta-reducer
我需要从 meta-reducer 或插件中发送一个动作。将此提供程序添加到应用程序模块时出现以下错误:
{
provide: NGXS_PLUGINS,
useFactory: myfunction,
deps: [Store],
multi: true
}
Cannot instantiate cyclic dependency! InternalStateOperations ("[ERROR
->]"): in NgModule AppModule
Cannot instantiate cyclic dependency! StateFactory ("[ERROR ->]"): in
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);
}}
模块有上述供应商。
MetaReducers 可以通过函数或服务实现 (Class)。
如果你通过一个函数实现它,你可以这样做:
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
函数来改变状态。
您可以在插件中注入商店,使用 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 示例,如果你想查看的话
编辑: 实际上,当您可以使用已经具有中间件的插件时,使用中间件是没有意义的。这样我们所要做的就是创建动作:
@Action(RequestLogout)
async requestLogout(context: StateContext<IAuthStateModel>) {
context.dispatch(new Navigate(['/login']));
context.dispatch(new StateResetAll());
}
中间件解决方案:
从技术上讲,提供的答案是不正确的,因为 {}
不会将应用程序状态重置为其默认值。
为了将来实施此功能的人员参考,我提供以下解决方案:
import { ActionType, getActionTypeFromInstance, NgxsNextPluginFn, NgxsPlugin, Store } from '@ngxs/store';
import { Injectable, Injector } from '@angular/core';
import { RequestLogout } from './auth.actions';
import { Navigate } from '@ngxs/router-plugin';
import { StateResetAll } from 'ngxs-reset-plugin';
@Injectable()
export class LogoutMiddleware implements NgxsPlugin {
constructor(
private injector: Injector,
) {
}
public handle(
state: any,
action: ActionType,
next: NgxsNextPluginFn,
): NgxsNextPluginFn {
if (getActionTypeFromInstance(action) === RequestLogout.type) {
const store = this.injector.get<Store>(Store);
store.dispatch(new Navigate(['/login']));
store.dispatch(new StateResetAll());
}
return next(state, action);
}
}
然后在你的应用程序模块中,你必须声明 LogoutMiddleware(有趣的是 meta-reducer 只是 redux 中间件的奇特名称)并导入 NgxsResetPluginModule。
providers: [
{
provide: NGXS_PLUGINS,
useClass: LogoutMiddleware,
multi: true,
},
...
],
imports: [
NgxsResetPluginModule.forRoot(),
...
],
我需要从 meta-reducer 或插件中发送一个动作。将此提供程序添加到应用程序模块时出现以下错误:
{
provide: NGXS_PLUGINS,
useFactory: myfunction,
deps: [Store],
multi: true
}
Cannot instantiate cyclic dependency! InternalStateOperations ("[ERROR ->]"): in NgModule AppModule
Cannot instantiate cyclic dependency! StateFactory ("[ERROR ->]"): in 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);
}}
模块有上述供应商。
MetaReducers 可以通过函数或服务实现 (Class)。
如果你通过一个函数实现它,你可以这样做:
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
函数来改变状态。
您可以在插件中注入商店,使用 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 示例,如果你想查看的话
编辑: 实际上,当您可以使用已经具有中间件的插件时,使用中间件是没有意义的。这样我们所要做的就是创建动作:
@Action(RequestLogout)
async requestLogout(context: StateContext<IAuthStateModel>) {
context.dispatch(new Navigate(['/login']));
context.dispatch(new StateResetAll());
}
中间件解决方案:
从技术上讲,提供的答案是不正确的,因为 {}
不会将应用程序状态重置为其默认值。
为了将来实施此功能的人员参考,我提供以下解决方案:
import { ActionType, getActionTypeFromInstance, NgxsNextPluginFn, NgxsPlugin, Store } from '@ngxs/store';
import { Injectable, Injector } from '@angular/core';
import { RequestLogout } from './auth.actions';
import { Navigate } from '@ngxs/router-plugin';
import { StateResetAll } from 'ngxs-reset-plugin';
@Injectable()
export class LogoutMiddleware implements NgxsPlugin {
constructor(
private injector: Injector,
) {
}
public handle(
state: any,
action: ActionType,
next: NgxsNextPluginFn,
): NgxsNextPluginFn {
if (getActionTypeFromInstance(action) === RequestLogout.type) {
const store = this.injector.get<Store>(Store);
store.dispatch(new Navigate(['/login']));
store.dispatch(new StateResetAll());
}
return next(state, action);
}
}
然后在你的应用程序模块中,你必须声明 LogoutMiddleware(有趣的是 meta-reducer 只是 redux 中间件的奇特名称)并导入 NgxsResetPluginModule。
providers: [
{
provide: NGXS_PLUGINS,
useClass: LogoutMiddleware,
multi: true,
},
...
],
imports: [
NgxsResetPluginModule.forRoot(),
...
],