From c2fa26516b7165f6bdc4c1938e35f7ea6280c120 Mon Sep 17 00:00:00 2001 From: arturovt Date: Sun, 17 Sep 2023 01:18:16 +0300 Subject: [PATCH] refactor: use `ReplaySubject` for take until notifiers This commit updates all `destroy$` subjects to be replayed subjects for consistency across implementations. This change ensures that no more subscriptions occur after any injectee is destroyed. --- packages/form-plugin/src/directive.ts | 4 +-- packages/router-plugin/src/router.state.ts | 25 ++++++++----------- .../src/internal/lifecycle-state-manager.ts | 4 +-- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/packages/form-plugin/src/directive.ts b/packages/form-plugin/src/directive.ts index 6d8f31739..bf3746dca 100644 --- a/packages/form-plugin/src/directive.ts +++ b/packages/form-plugin/src/directive.ts @@ -1,7 +1,7 @@ import { ChangeDetectorRef, Directive, Input, OnDestroy, OnInit } from '@angular/core'; import { FormGroup, FormGroupDirective } from '@angular/forms'; import { Actions, getValue, ofActionDispatched, Store } from '@ngxs/store'; -import { Observable, Subject } from 'rxjs'; +import { Observable, ReplaySubject } from 'rxjs'; import { debounceTime, distinctUntilChanged, filter, takeUntil } from 'rxjs/operators'; import { ResetForm, @@ -37,7 +37,7 @@ export class NgxsFormDirective implements OnInit, OnDestroy { private _updating = false; - private readonly _destroy$ = new Subject(); + private readonly _destroy$ = new ReplaySubject(1); constructor( private _actions$: Actions, diff --git a/packages/router-plugin/src/router.state.ts b/packages/router-plugin/src/router.state.ts index dfe48e5ed..0c760c07c 100644 --- a/packages/router-plugin/src/router.state.ts +++ b/packages/router-plugin/src/router.state.ts @@ -16,7 +16,8 @@ import { NgxsRouterPluginOptions, ɵNGXS_ROUTER_PLUGIN_OPTIONS } from '@ngxs/router-plugin/internals'; -import { Subscription } from 'rxjs'; +import { ReplaySubject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import { Navigate, @@ -71,10 +72,10 @@ export class RouterState implements OnDestroy { private _lastEvent: Event | null = null; - private _subscription = new Subscription(); - private _options: NgxsRouterPluginOptions | null = null; + private _destroy$ = new ReplaySubject(1); + @Selector() static state(state: RouterStateModel) { return state && state.state; @@ -100,7 +101,7 @@ export class RouterState implements OnDestroy { } ngOnDestroy(): void { - this._subscription.unsubscribe(); + this._destroy$.next(); } @Action(Navigate) @@ -133,13 +134,10 @@ export class RouterState implements OnDestroy { } private _setUpStoreListener(): void { - const subscription = this._store - .select(RouterState) - .subscribe((state: RouterStateModel | undefined) => { - this._navigateIfNeeded(state); - }); - - this._subscription.add(subscription); + const routerState$ = this._store.select(RouterState).pipe(takeUntil(this._destroy$)); + routerState$.subscribe((state: RouterStateModel | undefined) => { + this._navigateIfNeeded(state); + }); } private _navigateIfNeeded(routerState: RouterStateModel | undefined): void { @@ -171,7 +169,8 @@ export class RouterState implements OnDestroy { let lastRoutesRecognized: RoutesRecognized; - const subscription = this._router.events.subscribe(event => { + const events$ = this._router.events.pipe(takeUntil(this._destroy$)); + events$.subscribe(event => { this._lastEvent = event; if (event instanceof NavigationStart) { @@ -199,8 +198,6 @@ export class RouterState implements OnDestroy { this._reset(); } }); - - this._subscription.add(subscription); } /** Reacts to `NavigationStart`. */ diff --git a/packages/store/src/internal/lifecycle-state-manager.ts b/packages/store/src/internal/lifecycle-state-manager.ts index 0701a4421..66614b0f1 100644 --- a/packages/store/src/internal/lifecycle-state-manager.ts +++ b/packages/store/src/internal/lifecycle-state-manager.ts @@ -1,6 +1,6 @@ import { Injectable, OnDestroy } from '@angular/core'; import { NgxsBootstrapper } from '@ngxs/store/internals'; -import { EMPTY, Subject } from 'rxjs'; +import { EMPTY, ReplaySubject } from 'rxjs'; import { catchError, filter, @@ -21,7 +21,7 @@ import { NgxsLifeCycle, NgxsSimpleChange, StateContext } from '../symbols'; @Injectable({ providedIn: 'root' }) export class LifecycleStateManager implements OnDestroy { - private readonly _destroy$ = new Subject(); + private readonly _destroy$ = new ReplaySubject(1); constructor( private _store: Store,