# useObservable / toSignal
Many existing Angular applications makes use of RxJS / NgRx to manage state. With the planned introduction of signals-based reactivity in Angular we need to make sure that a good RxJS inter-operability story exsists.
This document explores possible options of bridging the Observables and signals world - focusing on _consuming_ observables.
## useObservable
One idea [we've explored in the past with GDEs](https://angular-team.slack.com/archives/C08M4JKNH/p1663085638927489) is the idea of the `useObservable` utility that could be used as follows:
```typescript!
@Component({
selector: 'my-component',
template: `
Hello, {{name()}}
`
})
class MyComponent {
// here names$ is an observable
name = useObservable(names$, 'Anonymous');
}
```
Notable points:
* the `useObservable` utlity returns a getter function which has the same signature as signals;
* the idea _is_ to expose a signal (so observables can participate in computeds etc.)
* the default value to `useObservable` assures that a resulting signal always has a value.
This propsal has several benefits:
* The value is available synchronously in all contexts (TS code and template) with the same API (getter function).
* Mitigates well know issues with the `async` pipe approach (effecitivelly eliminating the need for it):
* one can use the value in multiple places in the template, without the need for multiple subscriptions w/ multicast, or an outer *ngIf="obs$ | async as obs" alias;
* `ngIf`... TODO: list the `async` pipe problems we are solving
* Observables are automatically unsubscribed when a component is destroyed, greatly reducing cases where a manual subscription could be the source of memory leaks.
Implementation wise, the `useObservable` utilty could be as simple as (pseudo-code):
```typescript!
export function useObservable<T>(obs$: Observable<T>, initalValue: T): () => T {
const cdRef = inject(ChangeDetectorRef);
const valueSignal = createState(initalValue);
const unsub = obs$.subscribe((newValue) => {
cdRef.markForCheck();
value = newValue;
});
// TODO: new Angular API to unsubscribe, ex.:
inject(ViewRef).onDestroy(unsub);
return () => valueSignal();
}
```
Pros:
* very simple utility, well aligned with the longer-term, signal-based strategy
* solves number of problems with consuming observables /
Cons:
* the utility only works in the "injectable context" (component / directive / pipe creation)
Requires:
* work on the new API to register per-view destroy hooks
## converting observables to signals
A different, more generic approach would consist of having a utility function that convers any observable to signal, ex.:
```typescript!
const names$ = new BehaviorSubject('Pawel');
export const NAMES_TOKEN = new InjectionToken('Names as signal', {
factory() {
// I can convert Observable => signal anywhere, not "trapped" in components
return toSignal(names$, 'Anonymous')
},
});
@Component({
selector: 'my-component',
template: `
Hello, {{name()}}
`
})
class MyComponent {
name = inject(NAMES_TOKEN);
}
```
From the user point of view this utility has the similar ergonomics and benefits. Implementation wise, though, things are rather different:
```typescript!
export function toObservable<T>(obs$: Observable<T>, initalValue: T): () => T {
const valueSignal = createState(initalValue);
const unsub = obs$.subscribe((newValue) => {
value = newValue;
});
// **QUESTION**: who will unsubscribe????
return () => valueSignal();
}
```
**The challange here is the unsubscription**: generally speaking signals have no notation of "cleanup" so it is not obvious where the unsubscribe logic should go. For a general utility like this we might want to introduce the idea of a "cleanup context":
* signals, computations and effects need to be registered (created) in a wrapping cleanup context;
* signals, computations and effects can register cleanup hooks with the context;
* all the registered hooks are executed when context gets destroyed;
* cleanup context can be nested;
* there is an API to create a top-level cleanup context;
While the "cleanup context" idea would cover the use-case in question, it would also add complexity / API surface to the signals library.
## Other considerations
* semantics of Observable's emmiting completed / error
* "completed" is straighforward: a signal would keep returning the last emitted value
* "error" options:
* cache error value and keep re-throwing it in a getter <= probably the best option
* keep returning the last emitted value (this would effectivelly "swallow" errors)
* keep returning some well-known value representing / wrapping the error.
* default value: BehaviorSubject (always has value) vs. Observable (might emit asynchronously)