diff --git a/packages/store/src/internal/dispatcher.ts b/packages/store/src/internal/dispatcher.ts index 34a06247f..9ce57d839 100644 --- a/packages/store/src/internal/dispatcher.ts +++ b/packages/store/src/internal/dispatcher.ts @@ -1,11 +1,10 @@ -import { Injectable, NgZone } from '@angular/core'; +import { inject, Injectable, Injector, NgZone, runInInjectionContext } from '@angular/core'; import { EMPTY, forkJoin, Observable, of, Subject, throwError } from 'rxjs'; import { exhaustMap, filter, map, shareReplay, take } from 'rxjs/operators'; import { getActionTypeFromInstance } from '@ngxs/store/plugins'; import { ɵPlainObject, ɵStateStream } from '@ngxs/store/internals'; -import { compose } from '../utils/compose'; import { ActionContext, ActionStatus, InternalActions } from '../actions-stream'; import { PluginManager } from '../plugin-manager'; import { InternalNgxsExecutionStrategy } from '../execution/internal-ngxs-execution-strategy'; @@ -23,6 +22,8 @@ export class InternalDispatchedActionResults extends Subject {} @Injectable({ providedIn: 'root' }) export class InternalDispatcher { + private _injector = inject(Injector); + constructor( private _ngZone: NgZone, private _actions: InternalActions, @@ -72,7 +73,7 @@ export class InternalDispatcher { const prevState = this._stateStream.getValue(); const plugins = this._pluginManager.plugins; - return compose([ + return compose(this._injector, [ ...plugins, (nextState: any, nextAction: any) => { if (nextState !== prevState) { @@ -117,3 +118,33 @@ export class InternalDispatcher { .pipe(shareReplay()); } } + +type StateFn = (...args: any[]) => any; + +/** + * Composes a array of functions from left to right. Example: + * + * compose([fn, final])(state, action); + * + * then the funcs have a signature like: + * + * function fn (state, action, next) { + * console.log('here', state, action, next); + * return next(state, action); + * } + * + * function final (state, action) { + * console.log('here', state, action); + * return state; + * } + * + * the last function should not call `next`. + */ +const compose = + (injector: Injector, funcs: StateFn[]) => + (...args: any[]) => { + const curr = funcs.shift()!; + return runInInjectionContext(injector, () => + curr(...args, (...nextArgs: any[]) => compose(injector, funcs)(...nextArgs)) + ); + }; diff --git a/packages/store/src/utils/compose.ts b/packages/store/src/utils/compose.ts deleted file mode 100644 index 2c7337f49..000000000 --- a/packages/store/src/utils/compose.ts +++ /dev/null @@ -1,29 +0,0 @@ -export type StateFn = (...args: any[]) => any; - -/** - * Composes a array of functions from left to right. Example: - * - * compose([fn, final])(state, action); - * - * then the funcs have a signature like: - * - * function fn (state, action, next) { - * console.log('here', state, action, next); - * return next(state, action); - * } - * - * function final (state, action) { - * console.log('here', state, action); - * return state; - * } - * - * the last function should not call `next`. - * - * @ignore - */ -export const compose = - (funcs: StateFn[]) => - (...args: any[]) => { - const curr = funcs.shift()!; - return curr(...args, (...nextArgs: any[]) => compose(funcs)(...nextArgs)); - }; diff --git a/packages/store/tests/plugins.spec.ts b/packages/store/tests/plugins.spec.ts index 4655b4d7c..e072a623a 100644 --- a/packages/store/tests/plugins.spec.ts +++ b/packages/store/tests/plugins.spec.ts @@ -1,3 +1,4 @@ +import { assertInInjectionContext } from '@angular/core'; import { TestBed } from '@angular/core/testing'; import { NgxsModule, NGXS_PLUGINS, Store } from '@ngxs/store'; import { tap } from 'rxjs/operators'; @@ -16,6 +17,8 @@ describe('Plugins', () => { action: any, next: (state: any, action: any) => Observable ) { + assertInInjectionContext(logPlugin); + if (action.constructor && action.constructor.type === 'Foo') { pluginInvoked++; }