Reactivity in JavaScript

Reactivity in JavaScript

Hello folks,

In the previous article, we attempted to understand the core of reactive programming and explored a few of the high-level concepts with the help of real-world examples. In this article, we will try to touch upon real coding examples and visualize reactive programming in action.

How does a reactive JavaScript program look like?

Without spending much time on the theory, let us directly try to code a simple piece of the program. Consider we need to write a program that keeps the total price of the items. It's fairly simple. The total cost will be unit price multiplied by the quantity.

const price = {};
const quantity = {};

price.value = 5;
quantity.value = 2;
total = price.value * quantity.value;
console.log(total);  // 10

price.value = 10;
quantity.value = 3;
console.log(total);  // 10  (changing the price and quantity did not change total)

total = price.value * quantity.value;  // calculate the total passively
console.log(total);  // 30

In the above code snippet, the value of the price and quantity are set. Now we create a variable total which is dependent on values of quantity and price. As you can see, the total is displayed after the expression is evaluated. Later, the values of price and quantity are getting modified. Now, when you try to access the value of the total, it is still the old value. Total is not listening to its dependencies and updating itself. Every time the value of the price or the quantity changes, the code has to calculate the total passively.

This is how we code, isn't it? Yes. It's no surprise to us that the code is working as expected and we have written most of our code in this fashion. But what we have discussed in the previous article was about the examples of systems that are reactive. Let us see what the reactive version of the above code looks like.

const price = {};
const quantity = {};

const getterSetter = {
  get() {
    return this._value;
  },
  set(newValue) {
    this._value = newValue;
    publishChange();
  },
};

Object.defineProperty(price, "value", getterSetter);
Object.defineProperty(quantity, "value", getterSetter);

const publishChange = () => {
  total = price.value * quantity.value;
};

price.value = 5;
quantity.value = 2;
console.log(total);  // 10

price.value = 10;
quantity.value = 3;
console.log(total);  // 30 (Voila!!! value of total is changing)

If you do not understand the above program, no need to get demotivated. We are not worried about the syntax or the implementation. If you try to just observe the last few lines of code, the variable total is changing automatically when the value of price or quantity changes. Automatically??? It is not happening automatically though. Code is written in a fashion, in which it listens to the changes that happen to the value of the quantity or the price. On such an event or change, the total is recalculated. In other words, the variable total is reacting to the changes on which it is dependent.

Let us revisit reactive programming

In the name of reactive programming, did we just write more code than before? Even in the reactive approach, we got the same results as before. What is the point? Well, in the attempt to understand what is happening in the above reactive version of the program, such questions are common to popup.

If you compare passive and reactive codes side by side, at the first glance reactive code might look both complex and lengthy. But the concept which I am trying to explain here is about the flow of the control. In reactive code, if you ignore the top half of the code (which is more of a boilerplate code), you are focussing on what your code should do and not worried about updating the dependent code. As discussed before, reactive code knows what to perform when some change or event occurs. Reactive code reacts and does its work when data flows into it. The code is focused on performing its task alone and it does its best.

image.png

The image is the visualization of the understanding we have got. The component in the diagram is reactive. It listens to the incoming data or events and reacts to them. Here onwards let us call it data stream. No other component has to worry about updating our component, instead, those components will have to publish the data stream to which we react.

So, do I not need to check the other components in reactive programming at all? Of course, you will have to look into the other components only when you are interested in knowing which other components are responsible for making your component react. Whereas in passive programming, to understand the working of a component itself, you will have to look into all those dependent components.

If you have used any modern frameworks such as ReactJS, Angular, Vue, Svelte, etc. you have already written a lot of reactive programming. For example in ReactJS, you modify and update the state, and the view renders with the updated value. Gone are the old days, where you modify the value of a variable in JS, query the DOM element and then update it manually by setting its textContent or innerHTML.

Even frameworks and libraries are doing the imperative stuff which is abstracted away from the developers. Like the reactive code example we have seen above, frameworks manage to get it done for us and make our code simple and reactive.

Similarly, in Angular, you update a variable value in the typescript file and the template updates. A lot many frameworks in JavaScript have adopted reactive programming at their core and you might not even have realized that you have written tones of reactive code if you are a frontend developer already.

Reactive programming with native JavaScript

Now that we have scratched the surface of reactive programming by exploring a little bit of theory and code examples, let us widen our knowledge on some more concepts around reactive programming in JavaScript. We have already done that in one of the above code snippets, but are we just done with that?

Let's try to discuss a bit more about the data stream which we have already seen.

image.png

If you observe, the data inside the stream can vary. The data stream can be empty i.e there is no data that has flown into the component. It could also be possible that either a single value or multiple values are coming inside the data stream. In pure JavaScript, to consume a single value, we have functions. But is function reactive? No. We call the function when we need it. Not the other way around. What about Promise? Yes. Promise calls us once it is resolved or rejected. But can it give multiple values over time (asynchronously)? No. A promise can either get fulfilled or rejected and it will be its final state. Then, what about iterator? Iterator can give multiple values over time but again it is not reactive. It is just a special function (generator).

The entity which can be used for reactive code and also can produce multiple values synchronously or asynchronously is called Observables. Is it present in JavaScript? Not yet. There are external libraries that fill this gap, but the most famous one is RxJS. It is a reactive extension for JavaScript which provides observables, subjects along with many other features. If you wish to explore more about RxJS and reactive programming. Also do try to implement it in pure JavaScript code to feel the fun.