Skip to main content

What is a Source ?

We've seen how to create Observables, but how can we simply emit some values ?


note

Performing a synchronous read and write on observable values, is usually done through Signals, and remains the recommended way.

However, Sources are more generic, and give you fine control and direct access on such "observable values".


Definition of a Source

Let's write the interface of a Source:

interface ISource<GValue> {
readonly emit: IObserver<GValue>;
readonly subscribe: IObservable<GValue>;
}

A Source is simply a tuple composed of an Observer and an Observable.

Usually, they are tied together by a predefined algorithm.

Kind of Sources

@lirx/core comes with a list of predefined Sources, each having a specific usage.

The MulticastSource

A MulticastSource is used to emit one value to multiple Observers.

While plain Observables are unicast (each subscribed Observer owns an independent execution of the Observable), MulticastSource are multicast.

Internally to the MulticastSource, subscribe does not invoke a new execution that delivers values. It simply registers the given Observer in a list of Observers, similarly to how addListener usually works in other libraries and languages.

You can create a MulticastSource with the function createMulticastSource.

Here's a simple example demonstrating its usage .

const source = createMulticastSource<number>();

source.subscribe((value: string) => {
console.log('value - A:', value);
});

source.subscribe((value: string) => {
console.log('value - B:', value);
});

source.emit(1);
source.emit(2);

Output:

value - A: 1
value - B: 1
value - A: 2
value - B: 2

If we already have an Observable and want to "convert" it to a MulticastSource (share its values), we can use the ObservablePipe shareObservablePipe:

const subscribe = pipe$$(interval(1000), [
scan$$$<void, number>(count => (count + 1), 0),
share$$$<number>(),
]);

The ReplaySource

A ReplaySource caches all the received values and emit them each time we subscribe to it.

This is the perfect candidate if we have to replay the values sent by an Observable.

We can create one using the function createReplaySource, but usually we'll end up using the shortcut createMulticastReplaySource, or the ObservablePipe shareObservablePipeWithMulticastReplaySource.

The ReplayLastSource

A ReplayLastSource is like a ReplaySource, but it only caches the last received value.

This is the perfect candidate if we have to keep only the last emitted value.

We can create one using the function createReplayLastSource, but like the previous one, we'll usually end up using the shortcut createMulticastReplayLastSource, or the ObservablePipe shareObservablePipeWithMulticastReplayLastSource.

let$$

In most cases we'll use the shortcut let$$ to create a MulticastReplayLastSource represented as a tuple. It will act like a regular variable, but having the faculties of an Observable.

const [$firsName, firstName$] = let$$('Valentin');
const [$lastName, lastName$] = let$$(); // it's possible to omit the value, in this case, the Observable is uninitialized

const fullName$ = string$$`${firstName$} ${lastName$}`;

fullName$((value) => {
console.log(value);
});

lastName$('Richard');
// OUT => Valentin Richard

firstName$('Bob');
// OUT => Bob Richard

This is an elegant manner to create dynamic variables.

note

let$$ is the Observable equivalent of a Signal. However, unlike Signals, it doesn't capture its context, so it's not intended to work with effect nor computed. This choice, makes it more performant, optimizable, and pipeable with other Observables.