Skip to content

Commit

Permalink
feat(signal-store): reimplement toObservable with Subject instead of …
Browse files Browse the repository at this point in the history
…ReplaySubject
  • Loading branch information
mini-rx committed Oct 25, 2023
1 parent b177427 commit c8f6609
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 4 deletions.
4 changes: 4 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,7 @@ See the file for details.
This repository includes a file "deep-freeze.ts" originally copied from
https://github.com/jsdf/deep-freeze/blob/v1.1.1/index.js, public domain licensed.
See the file for details.

This repository includes a file "mini-rx-to-observable.ts" originally copied from
https://github.com/angular/angular/blob/16.2.10/packages/core/rxjs-interop/src/take_until_destroyed.ts, MIT style licensed.
See the file for details.
5 changes: 3 additions & 2 deletions libs/signal-store/src/lib/connect.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { DestroyRef, EnvironmentInjector, inject, Signal } from '@angular/core';
import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { Observable } from 'rxjs';
import { Action, OperationType, StateOrCallback } from '@mini-rx/common';
import { miniRxIsSignal } from './utils';
import { miniRxToObservable } from './mini-rx-to-observable';

export function createConnectFn<StateType>(
dispatch: (
Expand All @@ -22,7 +23,7 @@ export function createConnectFn<StateType>(
keys.forEach((key) => {
const observableOrSignal: Observable<ValueType> | Signal<ValueType> = dict[key];
const obs$ = miniRxIsSignal(observableOrSignal)
? toObservable(observableOrSignal, { injector })
? miniRxToObservable(observableOrSignal, { injector })
: observableOrSignal;
obs$.pipe(takeUntilDestroyed(destroyRef)).subscribe((v) => {
dispatch(
Expand Down
54 changes: 54 additions & 0 deletions libs/signal-store/src/lib/mini-rx-to-observable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Credits go to Angular
// Copied from with small modifications: https://github.com/angular/angular/blob/16.2.10/packages/core/rxjs-interop/src/take_until_destroyed.ts

/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {
assertInInjectionContext,
DestroyRef,
effect,
inject,
Injector,
Signal,
untracked,
} from '@angular/core';
import { ToObservableOptions } from '@angular/core/rxjs-interop';
import { Observable, Subject } from 'rxjs';

// Reimplemented `toObservable` from Angular
// Use Subject instead of ReplaySubject (which is more lightweight and sufficient for internal use in MiniRx)
export function miniRxToObservable<T>(
source: Signal<T>,
options?: ToObservableOptions
): Observable<T> {
!options?.injector && assertInInjectionContext(miniRxToObservable);
const injector = options?.injector ?? inject(Injector);
const subject = new Subject<T>();

const watcher = effect(
() => {
let value: T;
try {
value = source();
} catch (err) {
untracked(() => subject.error(err));
return;
}
untracked(() => subject.next(value));
},
{ injector, manualCleanup: true }
);

injector.get(DestroyRef).onDestroy(() => {
watcher.destroy();
subject.complete();
});

return subject.asObservable();
}
5 changes: 3 additions & 2 deletions libs/signal-store/src/lib/rx-effect.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { DestroyRef, inject, Signal } from '@angular/core';
import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { isObservable, Observable, Subject } from 'rxjs';
import { defaultEffectsErrorHandler } from '@mini-rx/common';
import { miniRxIsSignal } from './utils';
import { miniRxToObservable } from './mini-rx-to-observable';

export function createRxEffectFn() {
const destroyRef = inject(DestroyRef);
Expand Down Expand Up @@ -33,7 +34,7 @@ export function createRxEffectFn() {
) => {
// If we detect a Signal: convert Signal to Observable
observableOrValue = miniRxIsSignal(observableOrValue)
? toObservable(observableOrValue)
? miniRxToObservable(observableOrValue)
: observableOrValue;

isObservable(observableOrValue)
Expand Down

0 comments on commit c8f6609

Please sign in to comment.