RxJS: What and Why

RxJS offers a powerful functional approach for dealing with events and with integration points into a growing number of frameworks, libraries and utilities. But learning RxJS and reactive programming can be difficult, there are a lot of new concepts, big API service and a fundamental shift and mindset from imperative to declarative style.

These days there is increased complexity in the frontend, we need to manage UI events and coordinate updates in real time. We need to manage the growing asynchronous activity in our apps in a way that is reliable, readable and extensibile.

RxJS was built to solve these problems, it builds over the observer and iterator patterns, introducing the observable type to solve the complexity that is written above. Using observables for streams of data or events, for example a mouse clicks or responses from a network requests or web socket connection. This stream expresses observables that simply represent data that is sequence over time. We can listen to these streams by subscribing and supplying callbacks to the invoked when a new value arrives, when an error occurs or when stream has completed.

observer pattern in rxjs example
observer pattern in rxjs example

This is known as a push base approach, you turn the control of these functions over to the producer of data and in this case the observable. The observable then pushes the observer data by invoking these callbacks when they arrive. This is the essence of reactive programming in RxJS. We actually define how to react by registering functions to express the flow of data through our streams as it arrives.

The ability to create an observe streams is the foundation of RxJS, the idea of being able to register callbacks for events is not new, check the example below:


function doSomething(event) {
  // perform action
}

const updateButton = document.getElementById('update-button');

// standart event listener
updateButton.addEventListener('click', doSomething);

//rxjs
fromEvent(updateButton, 'click').subscribe(doSomething);

But the real power of RxJS is in the built in operator functions, with these operators you can compose the streams.

The below is an imperative solution In vanilla js:


function(callback, timeout) {
  let timer;
  timeout = timeout || 500;

  document.mousedown(function() {
    timer = setTimeout(function() { callback(); }, timeout);
    return false;
  });

  document.mouseup(function() {
    clearTimeout(timer);
    return false;
  });
}

With RxJS it will be expressed declaratively with a few operators (without setTimeout and variables):


mousedown$.pipe(
  mergeMap(e => of(e).pipe(
    delay(700),
    takeUntil(mouseUp$)
  ))
);

Another example that for sure you encountered is work with JavaScript collections.these can be applied with observables through operators. 

The below operation in vanilla JS on an array:


[1,2,3,4,5].map(value => value + 10);

The same operation can be performed with observables and map operator as event accrue in real time:


fromEvent(
  map(e => e.clientX)
).subscribe(
  // side effect
);

Like when we filter values in arrays, we can filter events as they flow through the observables with filter operator:


[1,2,3,4,5]
  .map(value => value + 10)
  .filter(value => value % 2);

Any operation that you can perform on a collection of data synchronously, you can also perform on a stream of events asynchronously with RxJS and observables.

The RxJS operators or RxJS often referred to as Lodash for events but while loadsh methods operate on data being pulled from the collection, RxJS operators react to data that is pushed from the observable to the observer.

Reactive Development

RxJs helps us to write code in a reactive way. what does it means?

to understand it, lets see a simple example in math:


x = 3
y= 2
z = x + y  // --> what is the value of z?  5!
x = 10  // --> the value of z is still 5!

In a procedural programing, the value is assigned when the expression is first evaluated. it means that “z” does not react to changes in “x” or “y”.

reacting to changes in our application is very important, and it can be achieve with:

  • JavaScript Getter (The get Keyword)
  • event handler

we can use the getter or event handler to react to changes but we cant for example to notify it to other components in our app if needed.

But with RxJS we can declare a variable that we want it to be reactive. we want to observe its changes so we call it an observable. when ever the value updates, the observable emits a notification with the updated value. The application can then react every time it observes an emission. in each time the observable emits a notification, the new value might run through some calculation that eventually will give a result data.

we can use RxJS with classic imperative programing where a value is assigned when expression is first evaluated or we can use RxJS in a a reactive approach where variables obsrve and react to changes and these changes are propagated.


// Imperative
x = 3
y = 2
z = x + y  // --> what is the value of z?  5!
x = 10  // --> the value of z is still 5!

// Reactive
x = 5
y = 3
// we use the $ sign to visually tell that this variable can be observed as it react to changes. (Observable in this case)
z$ = x + y  
x = 10  
// $z emits 8, then 13

Formal definitions of reactive development:

  • A declarative programming paradigm concerned with data stream and the propagation of change.
  • Code is reactive when an input change leads to an automatic change in output.

When using reactive development techniques, our code can easly react to :

  • User actions
  • State changes
  • Combine data streams
  • communicate between components
  • Error handling
  • Manage state

Summary

RxJS is a library for observing and reacting to data and events by using observable sequences. RxJS help us to manage and manipulate the data needed in our applications, especially asynchronies and event based data. RxJS advantges are:

  • One technique for all types of data.
  • Composing data easily.
  • Produce multiple values over time + push model to notify our code when specific action happen = easier way to watch and react to user interactions or data changes.
  • Lazy – evaluation does not start until subscription.
  • Built in error handling.
  • Canceling asynchronies actions is possible.
  • Reactive and declarative development.