Much Fun with RxJS-Autorun
Tags: angular, javascript, typescript, webdev
Published: 2020-10-27 15:12:43

Hi! 👋

Today I'll show you some tricks using [rxjs](https://rxjs.dev/) and [rxjs-autorun](https://github.com/kosich/rxjs-autorun) that we reviewed in the previous post. Let's quickly recap what it does:

1. you pass it an expression that uses some streams
2. whenever those streams emit, autorun runs the expression with new values
3. you get a stream of those evaluations results

**Now let's go fast explore what we can do with it!**

<a href="https://vine.co/v/iPEMitrVYz5"><img alt="impatient doggy" src="https://media.giphy.com/media/13ByqbM0hgfN7y/giphy.gif" width="420" /></a>

## Mapping a single stream: 🌱 🌿 🌳

The most basic usage: we have a stream `t` of growing integer values: `0`, `1`, `2`, etc ([RxJS timer](https://thinkrx.io/rxjs/timer/) will create us one). And we want to substitute that integer with a string: `"even"` or `"odd"`:

```ts
const t = timer(0, 1_000);
computed(() => $(t) % 2 ? 'odd' : 'even');
// Result:
// > even > odd > even > odd …
```

**Explanation:** `$(t)` will wait until stream `t` emits a value. Then with every value emission, `computed` will re-evaluate its expression, putting the result into the output stream.

## Combinations: 📦 + 🎀 = 🎁 

By tracking multiple streams inside expressions we can combine emissions from these streams:

```ts
import { timer, of } from 'rxjs';
import { computed, $ } from 'rxjs-autorun';

const a = timer(0, 1_000);
const b = of('🐇');
computed(() => $(a) + ' - ' + $(b))
// > 0 - 🐇 > 1 - 🐇 > 1 - 🐇 …
```

Similarly to combining into strings, we can combine into Arrays:

```ts
computed(() => [ $(a), $(b) ])
// > [ 0, 🐇 ] > [ 1, 🐇 ] …
```

Objects:

```ts
computed(() => ({ a: $(a), b: $(b) }))
// > { a: 0, b: 🐇 } > { a: 1, b: 🐇 } …
```

or even call functions!

```ts
function toString(count, animal) {
  return (count < 3 ? 'some' : 'many') + animal;
}
computed(() => toString( $(a), $(b) ))
// > some 🐇 > some 🐇 … > many 🐇 …
```

## Switching: 🌤 🌧

Now, imagine we have a function `getWeather` that returns an Observable with the weather forecast for a given city. Using the same `?:` from the first example we could create a widget to show weather for two cities:

```ts
const t = timer(0, 1_000);
const nice = getWeather('Nice'); // => Observable<'Nice: 🌤'>
const cannes = getWeather('Cannes'); // => Observable<'Cannes: 🌧'>
computed(() => $(t) % 2 ? $(nice) : $(cannes));
// > Cannes: 🌧 > Nice: 🌤 > Cannes: 🌧 > Nice: 🌤 …
```

## Tricks: 🐇 🎩 

Now, remember I said that `$(…)` will wait for the stream to emit its first value before continuing evaluation. Let's do some tricks exploiting this `rxjs-autorun` feature!

### Filtering

`computed` will wait for every observable to emit in order to produce a value. But what if we pass it a never emitting Observable: [NEVER](https://rxjs.dev/api/index/const/NEVER)? Correct, this will pause emission until other tracked Observable emits:

```ts
const a = timer(0, 1_000);
computed(() => $(a) % 2 ? $(NEVER) : $(a) + ' even' );
// > 0 even > 2 even > 4 even …
```

### Take while

Similarly to `NEVER`, we can exploit awaiting by passing it an Observable that completes never ever emitting a value: [EMPTY](https://rxjs.dev/api/index/const/EMPTY). If an expression relies on a stream that we know won't emit a value — then surely the resulting Observable won't emit either! So `computed` completes:

```ts
const a = timer(0, 1_000);
const c = computed(() => $(a) < 5 ? $(a) : $(EMPTY));
// > 0 > 1 > 2 > 3 > 4 > COMPLETE!
```

_NOTE: this feature is in beta-testing now and will be available with the next release_

## Bonus: 🙂

I showed you two functions: `computed` to run expressions and `$` to track values. But `$` has a sibling! A `_` function, similarly to `$`, will read the current value of a stream but **it won't trigger expression re-evaluation if that stream updates!**

Now, imagine the examples above if you mix `$` and `_`. Got you thinking, eh? Then imagine that all the `computed` streams can be used in other `computed` expressions!

## 🙂 → 😲 → 🤯

## Outro: 🛸💨

You'll find the docs and the library here: [github.com/kosich/rxjs-autorun](https://github.com/kosich/rxjs-autorun)

I hope you had fun! If you enjoyed reading — please, indicate that with ❤️ 🦄 📘 buttons — it helps a lot!

Follow me here and on [twitter](https://twitter.com/kddsky) for more RxJS, React, and JS posts!

**Thank you for reading this article! Stay reactive and have a nice day** 🙂

Cya! 👋

## Psst.. need something more to read?

I got you covered:

- ["Turn a Stream of Objects into an Object of Streams"](https://dev.to/rxjs/turn-a-stream-of-objects-into-an-object-of-streams-2aed)

- ["Fetching Data in React with RxJS and <$> fragment"](https://dev.to/rxjs/fetching-data-in-react-with-rxjs-and-lt-gt-fragment-54h7)

- ["Queries for Observables: Crazy & Simple!"](https://dev.to/kosich/queries-for-observables-crazy-simple-15h3)

- ["Intro to Recks: Rx+JSX experiment"](https://dev.to/kosich/recks-rxjs-based-framework-23h5)

## 😉

<!--

**switch map**


**string #2**

```ts
const root = document.getElementById("root");
const n = timer(0, 1000);
tracktag`I see ${n} 🦔`.subscribe(t => (root.innerText = t));
```

https://stackblitz.com/edit/rxjs-autorun-tagged-strings

**string #3**

```ts
const root = document.getElementById("root");
const render = html$(root);
const n = timer(0, 1000);

const header = tag$`<h2>I see ${n} 🦔</h2>`;
const child = tag$`<p><b>Can you?!</b></p>`;
render`<div>
  <header>${header}</header>
  <section>${child}</section>
</div>`;
```

https://stackblitz.com/edit/rxjs-autorun-htmled-strings
-->