Skip to content

Commit

Permalink
refactor: replace ngOnDestroy with DestroyRef
Browse files Browse the repository at this point in the history
  • Loading branch information
arturovt committed Dec 24, 2024
1 parent 26bd22b commit a5af8f0
Show file tree
Hide file tree
Showing 9 changed files with 36 additions and 41 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ $ npm install @ngxs/store@dev

### To become next patch version

- Refactor: Replace `ngOnDestroy` with `DestroyRef` [#2289](https://github.com/ngxs/store/pull/2289)
- Fix(store): Add root store initializer guard [#2278](https://github.com/ngxs/store/pull/2278)
- Fix(store): Reduce change detection cycles with pending tasks [#2280](https://github.com/ngxs/store/pull/2280)
- Fix(store): Complete action results on destroy [#2282](https://github.com/ngxs/store/pull/2282)
Expand Down
12 changes: 6 additions & 6 deletions packages/devtools-plugin/src/devtools.plugin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { inject, Injectable, Injector, NgZone, OnDestroy, ɵglobal } from '@angular/core';
import { DestroyRef, inject, Injectable, Injector, NgZone, ɵglobal } from '@angular/core';
import { Store } from '@ngxs/store';
import {
InitState,
Expand Down Expand Up @@ -27,7 +27,7 @@ const enum ReduxDevtoolsPayloadType {
* http://extension.remotedev.io/
*/
@Injectable()
export class NgxsReduxDevtoolsPlugin implements OnDestroy, NgxsPlugin {
export class NgxsReduxDevtoolsPlugin implements NgxsPlugin {
private _injector = inject(Injector);
private _ngZone = inject(NgZone);
private _options = inject(NGXS_DEVTOOLS_OPTIONS);
Expand All @@ -40,11 +40,11 @@ export class NgxsReduxDevtoolsPlugin implements OnDestroy, NgxsPlugin {

constructor() {
this.connect();
}

ngOnDestroy(): void {
this.unsubscribe?.();
this.globalDevtools?.disconnect();
inject(DestroyRef).onDestroy(() => {
this.unsubscribe?.();
this.globalDevtools?.disconnect();
});
}

/**
Expand Down
8 changes: 3 additions & 5 deletions packages/router-plugin/src/router.state.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NgZone, Injectable, OnDestroy, inject } from '@angular/core';
import { NgZone, Injectable, inject, DestroyRef } from '@angular/core';
import {
NavigationCancel,
NavigationError,
Expand Down Expand Up @@ -57,7 +57,7 @@ export const ROUTER_STATE_TOKEN = new StateToken<RouterStateModel>('router');
}
})
@Injectable()
export class RouterState implements OnDestroy {
export class RouterState {
private _store = inject(Store);
private _router = inject(Router);
private _serializer: RouterStateSerializer<RouterStateSnapshot> =
Expand Down Expand Up @@ -101,10 +101,8 @@ export class RouterState implements OnDestroy {
constructor() {
this._setUpStoreListener();
this._setUpRouterEventsListener();
}

ngOnDestroy(): void {
this._destroy$.next();
inject(DestroyRef).onDestroy(() => this._destroy$.next());
}

@Action(Navigate)
Expand Down
8 changes: 3 additions & 5 deletions packages/store/internals/src/state-stream.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable, OnDestroy, Signal, untracked } from '@angular/core';
import { DestroyRef, inject, Injectable, Signal, untracked } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';

import { ɵwrapObserverCalls } from './custom-rxjs-operators';
Expand All @@ -10,17 +10,15 @@ import { ɵPlainObject } from './symbols';
* @ignore
*/
@Injectable({ providedIn: 'root' })
export class ɵStateStream extends ɵOrderedBehaviorSubject<ɵPlainObject> implements OnDestroy {
export class ɵStateStream extends ɵOrderedBehaviorSubject<ɵPlainObject> {
readonly state: Signal<ɵPlainObject> = toSignal(this.pipe(ɵwrapObserverCalls(untracked)), {
manualCleanup: true,
requireSync: true
});

constructor() {
super({});
}

ngOnDestroy(): void {
// Complete the subject once the root injector is destroyed to ensure
// there are no active subscribers that would receive events or perform
// any actions after the application is destroyed.
Expand All @@ -29,6 +27,6 @@ export class ɵStateStream extends ɵOrderedBehaviorSubject<ɵPlainObject> imple
// for preventing memory leaks in server-side rendered apps, where a new `StateStream`
// is created for each HTTP request. If users forget to unsubscribe from `store.select`
// or `store.subscribe`, it can result in significant memory leaks in SSR apps.
this.complete();
inject(DestroyRef).onDestroy(() => this.complete());
}
}
8 changes: 4 additions & 4 deletions packages/store/src/actions/action-registry.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { Injectable, type OnDestroy } from '@angular/core';
import { DestroyRef, inject, Injectable } from '@angular/core';
import type { Observable } from 'rxjs';

export type ActionHandlerFn = (action: any) => Observable<unknown>;

@Injectable({ providedIn: 'root' })
export class NgxsActionRegistry implements OnDestroy {
export class NgxsActionRegistry {
// Instead of going over the states list every time an action is dispatched,
// we are constructing a map of action types to lists of action metadata.
// If the `@@Init` action is handled in two different states, the action
// metadata list will contain two objects that have the state `instance` and
// method names to be used as action handlers (decorated with `@Action(InitState)`).
private readonly _actionTypeToHandlersMap = new Map<string, Set<ActionHandlerFn>>();

ngOnDestroy(): void {
this._actionTypeToHandlersMap.clear();
constructor() {
inject(DestroyRef).onDestroy(() => this._actionTypeToHandlersMap.clear());
}

get(type: string) {
Expand Down
12 changes: 6 additions & 6 deletions packages/store/src/decorators/select/select-factory.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable, OnDestroy } from '@angular/core';
import { DestroyRef, inject, Injectable } from '@angular/core';

import { Store } from '../../store';
import { NgxsConfig } from '../../symbols';
Expand All @@ -8,17 +8,17 @@ import { NgxsConfig } from '../../symbols';
* in `@Select` decorator.
*/
@Injectable({ providedIn: 'root' })
export class SelectFactory implements OnDestroy {
export class SelectFactory {
static store: Store | null = null;
static config: NgxsConfig | null = null;

constructor(store: Store, config: NgxsConfig) {
SelectFactory.store = store;
SelectFactory.config = config;
}

ngOnDestroy(): void {
SelectFactory.store = null;
SelectFactory.config = null;
inject(DestroyRef).onDestroy(() => {
SelectFactory.store = null;
SelectFactory.config = null;
});
}
}
12 changes: 5 additions & 7 deletions packages/store/src/internal/action-results.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable, OnDestroy } from '@angular/core';
import { DestroyRef, inject, Injectable } from '@angular/core';
import { Subject } from 'rxjs';

import type { ActionContext } from '../actions-stream';
Expand All @@ -10,14 +10,12 @@ import type { ActionContext } from '../actions-stream';
* The dispatcher then asynchronously pushes the result from this stream onto the main action stream as a result.
*/
@Injectable({ providedIn: 'root' })
export class InternalDispatchedActionResults
extends Subject<ActionContext>
implements OnDestroy
{
ngOnDestroy(): void {
export class InternalDispatchedActionResults extends Subject<ActionContext> {
constructor() {
super();
// Complete the subject once the root injector is destroyed to ensure
// there are no active subscribers that would receive events or perform
// any actions after the application is destroyed.
this.complete();
inject(DestroyRef).onDestroy(() => this.complete());
}
}
8 changes: 4 additions & 4 deletions packages/store/src/internal/lifecycle-state-manager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { inject, Injectable, OnDestroy } from '@angular/core';
import { DestroyRef, inject, Injectable } from '@angular/core';
import { ɵNgxsAppBootstrappedState } from '@ngxs/store/internals';
import { getValue, InitState, UpdateState } from '@ngxs/store/plugins';
import { ReplaySubject } from 'rxjs';
Expand All @@ -12,7 +12,7 @@ import { NgxsLifeCycle, NgxsSimpleChange, StateContext } from '../symbols';
import { getInvalidInitializationOrderMessage } from '../configs/messages.config';

@Injectable({ providedIn: 'root' })
export class LifecycleStateManager implements OnDestroy {
export class LifecycleStateManager {
private _store = inject(Store);
private _internalStateOperations = inject(InternalStateOperations);
private _stateContextFactory = inject(StateContextFactory);
Expand All @@ -22,8 +22,8 @@ export class LifecycleStateManager implements OnDestroy {

private _initStateHasBeenDispatched?: boolean;

ngOnDestroy(): void {
this._destroy$.next();
constructor() {
inject(DestroyRef).onDestroy(() => this._destroy$.next());
}

ngxsBootstrap(
Expand Down
8 changes: 4 additions & 4 deletions packages/store/src/internal/state-factory.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable, Injector, OnDestroy, inject, ɵisPromise } from '@angular/core';
import { DestroyRef, Injectable, Injector, inject, ɵisPromise } from '@angular/core';
import {
ɵmemoize,
ɵMETA_KEY,
Expand Down Expand Up @@ -77,7 +77,7 @@ function cloneDefaults(defaults: any): any {
* @ignore
*/
@Injectable({ providedIn: 'root' })
export class StateFactory implements OnDestroy {
export class StateFactory {
private readonly _injector = inject(Injector);
private readonly _config = inject(NgxsConfig);
private readonly _stateContextFactory = inject(StateContextFactory);
Expand Down Expand Up @@ -132,8 +132,8 @@ export class StateFactory implements OnDestroy {
return context;
});

ngOnDestroy(): void {
this._actionsSubscription?.unsubscribe();
constructor() {
inject(DestroyRef).onDestroy(() => this._actionsSubscription?.unsubscribe());
}

/**
Expand Down

0 comments on commit a5af8f0

Please sign in to comment.