NGXS: Как использовать Store или установить State в метаредукторе - PullRequest
0 голосов
/ 30 января 2020

Мне нужно отправить действие из метаредуктора или плагина. Я получаю следующие ошибки при добавлении этого провайдера в модуль приложения:

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

Невозможно создать зависимость cycli c! InternalStateOperations ("[ERROR ->]"): в NgModule AppModule

Невозможно создать циклическую c зависимость! 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);
  }}

Модуль имеет вышеуказанного поставщика.

Ответы [ 2 ]

2 голосов
/ 11 февраля 2020

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 и получив экземпляр, но вы не можете отправить действие внутри плагина, потому что вы создадите бесконечное l oop.

Если вы хотите реализовать его через Сервис, вы можете сделать:

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 пример, если вы хотите проверить его

0 голосов
/ 20 апреля 2020

РЕДАКТИРОВАТЬ: На самом деле не имеет смысла использовать промежуточное ПО, когда вы можете использовать плагин, который уже имеет промежуточное ПО. Таким образом, все, что нам нужно сделать, это создать действие:

@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 ( Интересный факт, метаредуктор - это просто причудливое название для промежуточного программного обеспечения для редуксов) и импорта NgxsResetPluginModule.

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