RxJS Autorun Intro
Tags: rxjs, angular, webdev, javascript
Published: 2020-10-15 12:01:35

Hey, **RxJS** streamers! 🙋‍♂️

Today we're going to review a small library that re-evaluates an expression based on updates in streams it uses.

**tl;dr:** _docs and package at [github.com/kosich/rxjs-autorun](https://github.com/kosich/rxjs-autorun)_ 🔗

**Let's boldly explore it!**

![dog diving in snow](https://media.giphy.com/media/izLB2oZY9ZXzO/giphy.gif)

## It's a sweetened countdown

Our first example.

Say, we want to prettify each value on a [timer](https://thinkrx.io/rxjs/timer/) stream. So we'll write such an expression:

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

// timer would emit every second
const a = timer(0, 1_000);
// expression would concat every emission with a cake
const result = computed(() => $(a) + ' 🍰');
// now we should subscribe to the resulting stream
result.subscribe(x => console.log(x));
// > 0 🍰
// > 1 🍰
// > 2 🍰
// > …
```

**Explanation:** `computed` takes a function that uses some streams and re-evaluates it when those streams update. It returns an observable that you can manipulate further. And `$(a)` indicates that `a` is a stream and its updates should be listened to.

_So technically this expression is equivalent to `a.pipe( map(x => x + '🍰') )`_

But let's keep discovering what else this tiny lib can do:

## Infinite monkey theorem needs infinite bananas

Here we'll combine a timer that would represent a queue of our little 🐒 fellas with a stream of fetched bananas 🍌:

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

const a = timer(0, 1_000); // get some monkeys
const b = of('🍌').pipe(delay(2_000)); // fetch some treats
const result = computed(() => '🐒 #' + $(a) + ' gets ' + $(b)); // mix
result.subscribe(x => console.log(x)); // listen to result stream
// ...2s gap...
// > 🐒 #1 gets 🍌
// > 🐒 #2 gets 🍌
// > 🐒 #3 gets 🍌
// > …
```

<figcaption>BTW, did you know that <a href="https://en.wikipedia.org/wiki/Berry">banana is technically a berry?</a></figcaption>

Not hard at all, is it?

_This expression is similar to `combineLatest(a, b).pipe( map(([x,y]) => x + y) )`._

Let's review another multiple streams example:

## Who's up to some pizza?

The last trick we're gonna learn today is ability to read latest values without tracking their updates:

```ts
import { Subject } from 'rxjs';
import { computed, $, _ } from 'rxjs-autorun';

const a = new Subject(); // neighbours
const b = new Subject(); // food
computed(() => $(a) + ' likes ' + _(b))
  .subscribe(x => console.log(x));
a.next('🐈'); // nothing: b is still empty
b.next('🥛'); // > 🐈 likes 🥛
a.next('🐭'); // > 🐭 likes 🥛
b.next('🍕'); // nothing: _(b) doesn't trigger re-runs
a.next('🙋‍♂️'); // 🙋‍♂️ likes 🍕
```

**Explanation:** `_` function indicates that we need to take one value from a stream, but we don't want to recalculate our expression when this particular stream emits. So if an expression uses `$(a)` and `_(b)` — it would react only to `a` updates.

This also means that `computed(() => _(a))` expression would emit one value and immediately complete.

Okay, one really last thing before we wrap-up:

## Transformation

This time, try to guess what it is:

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

const a = timer(0, 1_000);
const b = of('💧');
const c = of('❄');
const result = computed(() => $(a) % 2 ? _(b) : _(c));
result.subscribe(x => console.log(x));
```

Indeed, this is capricious weather 🙂

_Actually, this expression is somewhat similar to [switchMap](https://thinkrx.io/rxjs/switchMap/)_

## Outro 😳

All the examples you can [try here](https://stackblitz.com/edit/rxjs-autorun-intro-examples?file=index.ts).

And there's more to the library, go [explore it yourself](https://github.com/kosich/rxjs-autorun)!

In the following articles we'll review how to filter emissions and how to manage subscriptions inside `rxjs-autorun` expressions. Not to miss those and other RxJS posts — follow me here and on [twitter](https://twitter.com/kddsky)!

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

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

Also I want to thank @fkrasnowski for lengthy discussions of this idea, @ryansolid for giving it a try and [Johan](https://github.com/Jopie64) for collaborating with me on this! 🙏

## 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)

## 😉