Skip to content

Aquent | DEV6

RxJS Basics

Written by: Kevin Wang

Intro

You’ve probably heard the buzz word – RxJS so many times, but still wondering what makes it so cool and popular? You’ve come to the right place. In this blog I’ll show you a few basics that can get you started.

What is RxJS?

RxJS is a library for reactive programming using Observables, to make it easier to compose asynchronous or callback-based code.  – RxJS official doc.

RxJS is a modern way to manage your asynchronous stuff like promises and avoid “promise hell.” Coding is all about solving problems, finding the right tool is crucial. In this case, RxJS not only handles asynchronous calls with multiple events, also it takes the concept of channelling a series of actions to the next level.

Observable – data source

An Observable is just a function that emits values over time from a data source. Think of a stream of data that arrives over time. The most common use case would be from events. This can be anything from the user clicking a button on the front end to data changing on the server and being sent to the client. Let’s see it in action.

// import the fromEvent operator
import { fromEvent } from 'rxjs';

// get button reference
const button = document.getElementById('button');

// create an observable of button clicks
const observable = fromEvent(button, 'click');

You can also find the code here:https://stackblitz.com/edit/rxjs-saxlnq?file=index.ts

We have utilized a helper function from RxJS to create our observable, but at this point the observable is cold — it isn’t doing anything right now, it is “cold” until there is a subscription.

Subscription – action

Subscription is the start of the action. If an observable is a faucet (data source), a subscription would be turning the handle (action).

To create a subscription, we just need to call the subscribe method.

observable.subscribe(event => console.log(event));

Voilà, now when you click the button you can see the MouseEvent being logged in the console.

It is important to know that each subscription will create a new execution context, meaning that two subscriptions on the same observable will create two event listeners.

It’s also important to unsubscribe when a subscription is no longer needed, especially if the same subscription can be created repeatedly by a user action, such as entering a view that creates a new subscription. In that scenario, you should call unsubscribe() on the subscription when the user leaves that view.  

Operators

Operators provide different ways to manipulate values from a source. This is what makes transform data easy.

Pipe

The pipe function acts as an assembly line in a factory, everything will go through the pipe before becoming the final product. It is very common to chain operators inside the pipe to transform, filter and manipulate data from the source. Let’s see an example.

Let’s say we have an observable that emits values from an input box. We can pass in different operators to get the results we need.

inputBox
  .pipe(
    debounceTime(500),
    distinctUntilChanged()
  )
  .subscribe(results => {
    // do whatever you want with the results here
  });
  • debounceTime
    • to reduce redundant processing, only continue to the next step when there are no new inputs in the past 500ms
  • distinctUntilChanged
    • if the value is the same, ignore it

Did you see what I just did there? Chaining operators! There are a lot of useful operators, I’m going to list some of the most commonly used ones.

import { of } from 'rxjs';
//emit values in sequence
const source = of(1, 2, 3, 4, 5);

//output: 1, 2, 3, 4, 5
const subscribe = source.subscribe(value => console.log(value));
  • map – transform data
import { of } from 'rxjs';
import { map } from 'rxjs/operators';

const source = of(1, 2, 3, 4, 5);

// subscribe to our source observable
const subscription = source
  .pipe(
    // multiply 2 to each emitted value
    map(value => value * 2)
  )
  // log: 2, 4, 6, 8, 10
  .subscribe(value => console.log(value));
  • skip – skip certain number of emitted values
import { of } from 'rxjs';
import { skip } from 'rxjs/operators';

const source = of(1, 2, 3, 4, 5);

const subscription = source
  .pipe(
    skip(3)
  )
  // log: 4, 5
  .subscribe(value => console.log(value));
  • take – opposite of skip, only take a specified number of values
import { of } from 'rxjs';
import { take } from 'rxjs/operators';

const source = of(1, 2, 3, 4, 5);

const subscription = source
  .pipe(
    take(3)
  )
  // log: 1, 2, 3
  .subscribe(value => console.log(value));
  • filter – just like JavaScript Array method
import { of } from 'rxjs';
import { filter } from 'rxjs/operators';

const source = of(1, 2, 3, 4, 5);

const subscription = source
  .pipe(
    filter(value => value < 2)
  )
  // log: 1
  .subscribe(value => console.log(value));

Conclusion

RxJS can be daunting and difficult to grasp at times, but once you get a hang of it, it will feel like building LEGO bricks. Trust me, learning RxJS is worth the investment. I hope this blog has given you some ideas to start with. There is a lot more to explore, make sure to check the links below:

https://itnext.io/understanding-rxjs-operators-ea4bc93d56e

https://angular.io/guide/rx-library

https://ultimatecourses.com/blog/rxjs-observables-observers-operators

Also, don’t forget to check out my colleague Eugene’s blog to dive deeper into retryWhen operator: