diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a3574bc7..1836787e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ $ npm install @ngxs/store@dev ### To become next patch version +- Refactor: Use field initializers for injectees [#2258](https://github.com/ngxs/store/pull/2258) - Fix(websocket-plugin): Do not dispatch action when root injector is destroyed [#2257](https://github.com/ngxs/store/pull/2257) ### 18.1.5 2024-11-12 diff --git a/packages/devtools-plugin/src/devtools.plugin.ts b/packages/devtools-plugin/src/devtools.plugin.ts index 551a9d216..129f6e4d8 100644 --- a/packages/devtools-plugin/src/devtools.plugin.ts +++ b/packages/devtools-plugin/src/devtools.plugin.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable, Injector, NgZone, OnDestroy, ɵglobal } from '@angular/core'; +import { inject, Injectable, Injector, NgZone, OnDestroy, ɵglobal } from '@angular/core'; import { Store } from '@ngxs/store'; import { InitState, @@ -8,12 +8,7 @@ import { } from '@ngxs/store/plugins'; import { tap, catchError } from 'rxjs/operators'; -import { - NGXS_DEVTOOLS_OPTIONS, - NgxsDevtoolsAction, - NgxsDevtoolsExtension, - NgxsDevtoolsOptions -} from './symbols'; +import { NGXS_DEVTOOLS_OPTIONS, NgxsDevtoolsAction, NgxsDevtoolsExtension } from './symbols'; const enum ReduxDevtoolsActionType { Dispatch = 'DISPATCH', @@ -33,17 +28,17 @@ const enum ReduxDevtoolsPayloadType { */ @Injectable() export class NgxsReduxDevtoolsPlugin implements OnDestroy, NgxsPlugin { + private _injector = inject(Injector); + private _ngZone = inject(NgZone); + private _options = inject(NGXS_DEVTOOLS_OPTIONS); + private devtoolsExtension: NgxsDevtoolsExtension | null = null; private readonly globalDevtools = ɵglobal['__REDUX_DEVTOOLS_EXTENSION__'] || ɵglobal['devToolsExtension']; private unsubscribe: VoidFunction | null = null; - constructor( - @Inject(NGXS_DEVTOOLS_OPTIONS) private _options: NgxsDevtoolsOptions, - private _injector: Injector, - private _ngZone: NgZone - ) { + constructor() { this.connect(); } diff --git a/packages/devtools-plugin/src/symbols.ts b/packages/devtools-plugin/src/symbols.ts index ddb4edbfb..630d57fdf 100644 --- a/packages/devtools-plugin/src/symbols.ts +++ b/packages/devtools-plugin/src/symbols.ts @@ -81,4 +81,6 @@ export interface NgxsDevtoolsOptions { traceLimit?: number; } -export const NGXS_DEVTOOLS_OPTIONS = new InjectionToken('NGXS_DEVTOOLS_OPTIONS'); +export const NGXS_DEVTOOLS_OPTIONS = new InjectionToken( + 'NGXS_DEVTOOLS_OPTIONS' +); diff --git a/packages/form-plugin/src/directive.ts b/packages/form-plugin/src/directive.ts index 5861777f1..8ceefddb3 100644 --- a/packages/form-plugin/src/directive.ts +++ b/packages/form-plugin/src/directive.ts @@ -1,4 +1,4 @@ -import { ChangeDetectorRef, Directive, Input, OnDestroy, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Directive, inject, Input, OnDestroy, OnInit } from '@angular/core'; import { FormGroup, FormGroupDirective } from '@angular/forms'; import { Actions, ofActionDispatched, Store } from '@ngxs/store'; import { getValue } from '@ngxs/store/plugins'; @@ -38,14 +38,12 @@ export class NgxsFormDirective implements OnInit, OnDestroy { private _updating = false; - private readonly _destroy$ = new ReplaySubject(1); + private _actions$ = inject(Actions); + private _store = inject(Store); + private _formGroupDirective = inject(FormGroupDirective); + private _cd = inject(ChangeDetectorRef); - constructor( - private _actions$: Actions, - private _store: Store, - private _formGroupDirective: FormGroupDirective, - private _cd: ChangeDetectorRef - ) {} + private readonly _destroy$ = new ReplaySubject(1); ngOnInit() { this._actions$ diff --git a/packages/router-plugin/src/router.state.ts b/packages/router-plugin/src/router.state.ts index 554341cc7..308116c57 100644 --- a/packages/router-plugin/src/router.state.ts +++ b/packages/router-plugin/src/router.state.ts @@ -1,4 +1,4 @@ -import { NgZone, Injectable, OnDestroy, Injector } from '@angular/core'; +import { NgZone, Injectable, OnDestroy, inject } from '@angular/core'; import { NavigationCancel, NavigationError, @@ -13,7 +13,6 @@ import { import { Action, createSelector, State, StateContext, StateToken, Store } from '@ngxs/store'; import { NavigationActionTiming, - NgxsRouterPluginOptions, ɵNGXS_ROUTER_PLUGIN_OPTIONS } from '@ngxs/router-plugin/internals'; import { ReplaySubject } from 'rxjs'; @@ -59,6 +58,12 @@ export const ROUTER_STATE_TOKEN = new StateToken('router'); }) @Injectable() export class RouterState implements OnDestroy { + private _store = inject(Store); + private _router = inject(Router); + private _serializer: RouterStateSerializer = + inject(RouterStateSerializer); + private _ngZone = inject(NgZone); + /** * Determines how navigation was performed by the `RouterState` itself * or outside via `new Navigate(...)` @@ -77,7 +82,7 @@ export class RouterState implements OnDestroy { private _lastEvent: Event | null = null; - private _options: NgxsRouterPluginOptions | null = null; + private _options = inject(ɵNGXS_ROUTER_PLUGIN_OPTIONS); private _destroy$ = new ReplaySubject(1); @@ -95,16 +100,7 @@ export class RouterState implements OnDestroy { state => state?.state?.url ); - constructor( - private _store: Store, - private _router: Router, - private _serializer: RouterStateSerializer, - private _ngZone: NgZone, - injector: Injector - ) { - // Note: do not use `@Inject` since it fails on lower versions of Angular with Jest - // integration, it cannot resolve the token provider. - this._options = injector.get(ɵNGXS_ROUTER_PLUGIN_OPTIONS, null); + constructor() { this._setUpStoreListener(); this._setUpRouterEventsListener(); } diff --git a/packages/storage-plugin/src/storage.plugin.ts b/packages/storage-plugin/src/storage.plugin.ts index e0d960f71..422e66797 100644 --- a/packages/storage-plugin/src/storage.plugin.ts +++ b/packages/storage-plugin/src/storage.plugin.ts @@ -1,4 +1,4 @@ -import { PLATFORM_ID, Inject, Injectable, inject } from '@angular/core'; +import { PLATFORM_ID, Injectable, inject } from '@angular/core'; import { isPlatformServer } from '@angular/common'; import { ɵPlainObject } from '@ngxs/store/internals'; import { @@ -13,7 +13,6 @@ import { import { ɵDEFAULT_STATE_KEY, ɵALL_STATES_PERSISTED, - NgxsStoragePluginOptions, ɵNGXS_STORAGE_PLUGIN_OPTIONS } from '@ngxs/storage-plugin/internals'; import { tap } from 'rxjs/operators'; @@ -27,16 +26,13 @@ const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode; @Injectable() export class NgxsStoragePlugin implements NgxsPlugin { + private _keysManager = inject(ɵNgxsStoragePluginKeysManager); + private _options = inject(ɵNGXS_STORAGE_PLUGIN_OPTIONS); private _allStatesPersisted = inject(ɵALL_STATES_PERSISTED); - - constructor( - private _keysManager: ɵNgxsStoragePluginKeysManager, - @Inject(ɵNGXS_STORAGE_PLUGIN_OPTIONS) private _options: NgxsStoragePluginOptions, - @Inject(PLATFORM_ID) private _platformId: string - ) {} + private _isServer = isPlatformServer(inject(PLATFORM_ID)); handle(state: any, event: any, next: NgxsNextPluginFn) { - if (isPlatformServer(this._platformId)) { + if (this._isServer) { return next(state, event); } diff --git a/packages/store/src/actions-stream.ts b/packages/store/src/actions-stream.ts index fe14c0fde..b33cbace5 100644 --- a/packages/store/src/actions-stream.ts +++ b/packages/store/src/actions-stream.ts @@ -1,4 +1,4 @@ -import { Injectable, OnDestroy } from '@angular/core'; +import { inject, Injectable, OnDestroy } from '@angular/core'; import { ɵOrderedSubject } from '@ngxs/store/internals'; import { Observable, Subject, filter, share } from 'rxjs'; @@ -50,10 +50,10 @@ export class InternalActions extends ɵOrderedSubject implements */ @Injectable({ providedIn: 'root' }) export class Actions extends Observable { - constructor( - internalActions$: InternalActions, - internalExecutionStrategy: InternalNgxsExecutionStrategy - ) { + constructor() { + const internalActions$ = inject(InternalActions); + const internalExecutionStrategy = inject(InternalNgxsExecutionStrategy); + const sharedInternalActions$ = internalActions$.pipe( leaveNgxs(internalExecutionStrategy), // The `InternalActions` subject emits outside of the Angular zone. diff --git a/packages/store/src/dev-features/ngxs-unhandled-actions-logger.ts b/packages/store/src/dev-features/ngxs-unhandled-actions-logger.ts index b9b24c30d..e9cd33744 100644 --- a/packages/store/src/dev-features/ngxs-unhandled-actions-logger.ts +++ b/packages/store/src/dev-features/ngxs-unhandled-actions-logger.ts @@ -1,8 +1,8 @@ -import { Inject, Injectable } from '@angular/core'; +import { inject, Injectable } from '@angular/core'; import { InitState, UpdateState, getActionTypeFromInstance } from '@ngxs/store/plugins'; import { ActionType } from '../actions/symbols'; -import { NgxsDevelopmentOptions, NGXS_DEVELOPMENT_OPTIONS } from './symbols'; +import { NGXS_DEVELOPMENT_OPTIONS } from './symbols'; @Injectable() export class NgxsUnhandledActionsLogger { @@ -12,7 +12,8 @@ export class NgxsUnhandledActionsLogger { */ private _ignoredActions = new Set([InitState.type, UpdateState.type]); - constructor(@Inject(NGXS_DEVELOPMENT_OPTIONS) options: NgxsDevelopmentOptions) { + constructor() { + const options = inject(NGXS_DEVELOPMENT_OPTIONS); if (typeof options.warnOnUnhandledActions === 'object') { this.ignoreActions(...options.warnOnUnhandledActions.ignore); } diff --git a/packages/store/src/execution/dispatch-outside-zone-ngxs-execution-strategy.ts b/packages/store/src/execution/dispatch-outside-zone-ngxs-execution-strategy.ts index 6795f985d..e72aefa1b 100644 --- a/packages/store/src/execution/dispatch-outside-zone-ngxs-execution-strategy.ts +++ b/packages/store/src/execution/dispatch-outside-zone-ngxs-execution-strategy.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable, NgZone, PLATFORM_ID } from '@angular/core'; +import { inject, Injectable, NgZone, PLATFORM_ID } from '@angular/core'; import { isPlatformServer } from '@angular/common'; import { NgxsExecutionStrategy } from './symbols'; @@ -6,17 +6,17 @@ import { getZoneWarningMessage } from '../configs/messages.config'; @Injectable({ providedIn: 'root' }) export class DispatchOutsideZoneNgxsExecutionStrategy implements NgxsExecutionStrategy { - constructor( - private _ngZone: NgZone, - @Inject(PLATFORM_ID) private _platformId: string - ) { + private _ngZone = inject(NgZone); + private _isServer = isPlatformServer(inject(PLATFORM_ID)); + + constructor() { if (typeof ngDevMode !== 'undefined' && ngDevMode) { - verifyZoneIsNotNooped(_ngZone); + verifyZoneIsNotNooped(this._ngZone); } } enter(func: () => T): T { - if (isPlatformServer(this._platformId)) { + if (this._isServer) { return this.runInsideAngular(func); } return this.runOutsideAngular(func); diff --git a/packages/store/src/execution/internal-ngxs-execution-strategy.ts b/packages/store/src/execution/internal-ngxs-execution-strategy.ts index eda8dafc8..3550778f7 100644 --- a/packages/store/src/execution/internal-ngxs-execution-strategy.ts +++ b/packages/store/src/execution/internal-ngxs-execution-strategy.ts @@ -1,12 +1,10 @@ -import { Injectable, Inject } from '@angular/core'; +import { Injectable, inject } from '@angular/core'; import { NgxsExecutionStrategy, NGXS_EXECUTION_STRATEGY } from './symbols'; @Injectable({ providedIn: 'root' }) export class InternalNgxsExecutionStrategy implements NgxsExecutionStrategy { - constructor( - @Inject(NGXS_EXECUTION_STRATEGY) private _executionStrategy: NgxsExecutionStrategy - ) {} + private _executionStrategy = inject(NGXS_EXECUTION_STRATEGY); enter(func: () => T): T { return this._executionStrategy.enter(func); diff --git a/packages/store/src/internal/dispatcher.ts b/packages/store/src/internal/dispatcher.ts index 34a06247f..0866333bf 100644 --- a/packages/store/src/internal/dispatcher.ts +++ b/packages/store/src/internal/dispatcher.ts @@ -1,4 +1,4 @@ -import { Injectable, NgZone } from '@angular/core'; +import { inject, Injectable, NgZone } from '@angular/core'; import { EMPTY, forkJoin, Observable, of, Subject, throwError } from 'rxjs'; import { exhaustMap, filter, map, shareReplay, take } from 'rxjs/operators'; @@ -23,14 +23,12 @@ export class InternalDispatchedActionResults extends Subject {} @Injectable({ providedIn: 'root' }) export class InternalDispatcher { - constructor( - private _ngZone: NgZone, - private _actions: InternalActions, - private _actionResults: InternalDispatchedActionResults, - private _pluginManager: PluginManager, - private _stateStream: ɵStateStream, - private _ngxsExecutionStrategy: InternalNgxsExecutionStrategy - ) {} + private _ngZone = inject(NgZone); + private _actions = inject(InternalActions); + private _actionResults = inject(InternalDispatchedActionResults); + private _pluginManager = inject(PluginManager); + private _stateStream = inject(ɵStateStream); + private _ngxsExecutionStrategy = inject(InternalNgxsExecutionStrategy); /** * Dispatches event(s). diff --git a/packages/store/src/internal/lifecycle-state-manager.ts b/packages/store/src/internal/lifecycle-state-manager.ts index e1a27b303..1d1fff32c 100644 --- a/packages/store/src/internal/lifecycle-state-manager.ts +++ b/packages/store/src/internal/lifecycle-state-manager.ts @@ -1,4 +1,4 @@ -import { Injectable, OnDestroy } from '@angular/core'; +import { inject, Injectable, OnDestroy } from '@angular/core'; import { ɵNgxsAppBootstrappedState } from '@ngxs/store/internals'; import { getValue, InitState, UpdateState } from '@ngxs/store/plugins'; import { ReplaySubject } from 'rxjs'; @@ -15,17 +15,15 @@ const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode; @Injectable({ providedIn: 'root' }) export class LifecycleStateManager implements OnDestroy { + private _store = inject(Store); + private _internalStateOperations = inject(InternalStateOperations); + private _stateContextFactory = inject(StateContextFactory); + private _appBootstrappedState = inject(ɵNgxsAppBootstrappedState); + private readonly _destroy$ = new ReplaySubject(1); private _initStateHasBeenDispatched?: boolean; - constructor( - private _store: Store, - private _internalStateOperations: InternalStateOperations, - private _stateContextFactory: StateContextFactory, - private _appBootstrappedState: ɵNgxsAppBootstrappedState - ) {} - ngOnDestroy(): void { this._destroy$.next(); } diff --git a/packages/store/src/internal/state-context-factory.ts b/packages/store/src/internal/state-context-factory.ts index 38ec2bac6..a2f32b73a 100644 --- a/packages/store/src/internal/state-context-factory.ts +++ b/packages/store/src/internal/state-context-factory.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { inject, Injectable } from '@angular/core'; import { getValue, setValue } from '@ngxs/store/plugins'; import { ExistingState, StateOperator, isStateOperator } from '@ngxs/store/operators'; import { Observable } from 'rxjs'; @@ -14,7 +14,7 @@ import { simplePatch } from './state-operators'; */ @Injectable({ providedIn: 'root' }) export class StateContextFactory { - constructor(private _internalStateOperations: InternalStateOperations) {} + private _internalStateOperations = inject(InternalStateOperations); /** * Create the state context diff --git a/packages/store/src/internal/state-operations.ts b/packages/store/src/internal/state-operations.ts index d177d2520..fa86277bd 100644 --- a/packages/store/src/internal/state-operations.ts +++ b/packages/store/src/internal/state-operations.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { inject, Injectable } from '@angular/core'; import { ɵStateStream } from '@ngxs/store/internals'; import { StateOperations, StatesAndDefaults } from '../internal/internals'; @@ -11,11 +11,9 @@ import { deepFreeze } from '../utils/freeze'; */ @Injectable({ providedIn: 'root' }) export class InternalStateOperations { - constructor( - private _stateStream: ɵStateStream, - private _dispatcher: InternalDispatcher, - private _config: NgxsConfig - ) {} + private _stateStream = inject(ɵStateStream); + private _dispatcher = inject(InternalDispatcher); + private _config = inject(NgxsConfig); /** * Returns the root state operators. diff --git a/packages/store/src/store.ts b/packages/store/src/store.ts index 07d4f7a88..87b46ccdb 100644 --- a/packages/store/src/store.ts +++ b/packages/store/src/store.ts @@ -1,4 +1,4 @@ -import { computed, Inject, Injectable, Optional, Signal } from '@angular/core'; +import { computed, inject, Injectable, Signal } from '@angular/core'; import { Observable, of, @@ -30,6 +30,12 @@ type ActionOrArrayOfActions = T extends (infer U)[] ? NonNullable[] : NonN @Injectable({ providedIn: 'root' }) export class Store { + private _stateStream = inject(ɵStateStream); + private _internalStateOperations = inject(InternalStateOperations); + private _config = inject(NgxsConfig); + private _internalExecutionStrategy = inject(InternalNgxsExecutionStrategy); + private _stateFactory = inject(StateFactory); + /** * This is a derived state stream that leaves NGXS execution strategy to emit state changes within the Angular zone, * because state is being changed actually within the `` zone, see `InternalDispatcher#dispatchSingle`. @@ -40,17 +46,8 @@ export class Store { shareReplay({ bufferSize: 1, refCount: true }) ); - constructor( - private _stateStream: ɵStateStream, - private _internalStateOperations: InternalStateOperations, - private _config: NgxsConfig, - private _internalExecutionStrategy: InternalNgxsExecutionStrategy, - private _stateFactory: StateFactory, - @Optional() - @Inject(ɵINITIAL_STATE_TOKEN) - initialStateValue: any - ) { - this.initStateStream(initialStateValue); + constructor() { + this.initStateStream(); } /** @@ -146,7 +143,8 @@ export class Store { return makeSelectorFn(runtimeContext); } - private initStateStream(initialStateValue: any): void { + private initStateStream(): void { + const initialStateValue: any = inject(ɵINITIAL_STATE_TOKEN); const value = this._stateStream.value; const storeIsEmpty = !value || Object.keys(value).length === 0; diff --git a/packages/websocket-plugin/src/websocket-handler.ts b/packages/websocket-plugin/src/websocket-handler.ts index 562f3375a..cd3bb4f27 100644 --- a/packages/websocket-plugin/src/websocket-handler.ts +++ b/packages/websocket-plugin/src/websocket-handler.ts @@ -1,4 +1,4 @@ -import { Injectable, Inject, NgZone, inject, DestroyRef } from '@angular/core'; +import { Injectable, NgZone, inject, DestroyRef } from '@angular/core'; import { Actions, Store, ofActionDispatched } from '@ngxs/store'; import { getValue } from '@ngxs/store/plugins'; import { ReplaySubject, Subject, fromEvent, takeUntil } from 'rxjs'; @@ -18,6 +18,11 @@ import { @Injectable({ providedIn: 'root' }) export class WebSocketHandler { + private _store = inject(Store); + private _ngZone = inject(NgZone); + private _actions$ = inject(Actions); + private _options = inject(NGXS_WEBSOCKET_OPTIONS); + private _socket: WebSocket | null = null; private readonly _socketClosed$ = new Subject(); @@ -26,12 +31,7 @@ export class WebSocketHandler { private readonly _destroy$ = new ReplaySubject(1); - constructor( - private _store: Store, - private _ngZone: NgZone, - private _actions$: Actions, - @Inject(NGXS_WEBSOCKET_OPTIONS) private _options: NgxsWebSocketPluginOptions - ) { + constructor() { this._setupActionsListeners(); const destroyRef = inject(DestroyRef);