What is Reactivity?  🤯
Tags: javascript, react, ember, webdev
Published: 2020-07-12 19:48:27

***Reactivity in a framework is a declarative programming model that takes care of keeping the DOM(Document Object Model) in sync with the updates to current state***

I know that it's hard to sip, let's get practical so that we solidify our mental models and get a good hold of it!

Let's code up a plain old counter by hand. With the advent of many javascript frameworks and libraries, it is a pretty easy task to accomplish. Will it be the same when developed with plain javascript?

Forget all the frameworks and libraries, Your only tool is **javascript** now and just get ready for the adventure!

<img src="https://media.giphy.com/media/dujg3dNjrf119zBXYD/giphy.gif" alt="Adventure!">

***index.html***:

<img src="https://i.imgur.com/pkGzMpw.png" width="250" height="250" alt="Index HTML">

Our counter will be rendered into `#app`.

***index.js***:

``` 
class Counter {

  count = 0;

  handleIncrement = () => {
    this.count++;
  };

  handleDecrement = () => {
    this.count--;
  };

}

```
I'm defining a class `Counter`, with a property `count` that defaults to `0` and two methods `handleIncrement`, `handleDecrement` that handles increment and decrement actions respectively. Our **current state** is the `count` property. Whenever the state is updated, our DOM should be synced up. It shouldn't be stale.

Since we are dealing with plain JS, we should be creating our increment and decrement buttons by hand right? That's what our next task is!

***index.js***:

```

  setUpButton(action) {
    const actionHash = {
      Increment: this.handleIncrement,
      Decrement: this.handleDecrement
    };
    const button = document.createElement("BUTTON");
    button.textContent = action;
    button.onclick = actionHash[action];
    return button;
  }

```

Our `setupButton` method ensures that It creates a button and associates the respective `onclick` handler according to the `action` passed as an argument. So we are done with the functionality. Not bad till now. Let's get it into `DOM`. We should be coding up our `render` method now!

***index.js***:

```

  render() {

    const app = document.getElementById("app");
    app.innerHTML = "";
    const count = document.createElement("DIV");
    count.textContent = this.count;
    const elementsToAppend = [
      count,
      this.setUpButton("Increment"),
      this.setUpButton("Decrement")
    ];
    const fragment = document.createDocumentFragment();
    elementsToAppend.forEach(element => {
      fragment.append(element);
    });
    app.appendChild(fragment);

  }

```

This is more of a **straight-forward** implementation of `render` method. DOM should be kept in sync with our state `count`. So we are clearing up any stale elements that were previously rendered at first by setting `innerHTML` to an empty `string`. We are creating a `div` element that renders our `count` value. Then we set up both our increment and decrement buttons and finally we append everything to the `#app` element.

Hurray! we are done soon. Let's check whether it's working.

***index.js***:

``` new Counter().render(); ```
<br>
***Output*** 🤯

<img src="https://i.imgur.com/nTHdgWK.gif" alt="Result">

<img src="https://media.giphy.com/media/11tIB893VLShXi/giphy.gif" alt="OOPS!">

Oops, it didn't work as expected 😱

While checking our code we can find that, once we update our state we've **failed** to render our app again! That's the cause. Let's fix it 🛠

***index.js***:

```

  handleIncrement = () => {
    this.count++;
    this.render();
  };
  handleDecrement = () => {
    this.count--;
    this.render();
  };

```

Finally 😅

<img src="https://i.imgur.com/RLYIt1e.gif" alt="Result">

The complete source code can be found [here](https://codesandbox.io/s/plain-js-counter-n846r).

OMG! see how imperative our solution is 😓. What if we include a magic layer that takes care of these **nitty-gritty** things. That is, whenever our current state updates, our app should magically **rerender** declaratively. That's the way to go, right? What if we add another state in the future and failed to do the same? This solution is **less maintainable** and not future proof.

To the surprise, the modern javascript frameworks and libraries actually act as the **magic layer** underhood that takes care of these low-level tasks and makes you more productive by letting you concentrate entirely on the **app business logic**. The DOM will be in-sync with the state updates and that's a promise given by modern frameworks and libraries.
And also we can't simply rerender the whole `app` for a single state change. These tools also ensure that they efficiently update the `DOM` and only `re-render` the parts that are only necessary.

These tools have their own ways of handling state management.

***How does React handle it?***

**React** achieves state tracking via the `useState` API in functional components.

<img src="https://i.imgur.com/4Hx1fmF.png" alt="React">

With `useState`, now the solution is more maintainable and readable and less error-prone. Future updates can be done seamlessly.

`useState` function imported from `react` when invoked, returns an array. It contains two elements, the first one denotes the state variable itself, while the second element references a function that can be invoked to update that particular state variable. You can't simply use `this.count++` or `this.count--` directly as we do in plain JS. We should only use the respective state updater functions. This solution is more declarative than the previous one that we hand-coded with plain JS.

But what if I say that there is a more elegant way for achieving this?

<img src="https://media.giphy.com/media/5BUJlxujXJwR8EiSB4/giphy.gif" alt="OMG!">

**Ember**, a framework for ambitious web applications provides us some great APIs that are more natural-looking and syntactically very declarative. You can be free from using any state updater functions like `this.setState()`. Just `count++` or `count--` is enough. This is how we do in javascript right?

**Octane edition** is the latest update in `Ember`. This has amazed me with lots of cool new features and a more organized declarative programming model. If I had to pick one out of them, the new Reactivity model earns the medal, to be honest.
Let's see how our counter can be implemented with `Ember` 🤗

***Counter.js***:

<img src="https://i.imgur.com/h9SOIex.png" alt="Ember">


***Counter.hbs***:

<img src="https://i.imgur.com/dMiPyNc.png" alt="HBS">

I personally feel this approach to be more natural. You just tell `Ember` which properties you wanna keep in the state. `Ember` automatically tracks that particular property and keeps the `DOM` in-sync on updates to it. Also, your markup is now split into a separate `handlebars` file, so that your business logic now becomes **less clunky** and **more readable** 🤩

This is a lot for now. Let me know your thoughts regarding our approach in the comments below.

Interested to know more about how `@tracked` imported from `@glimmer/tracking` achieves this complex work underhood?

Want to know how `@tracked` keeps the track of different state properties and triggers rerender based on the updates on them?

Curious to know about their **internals**?

This is what exactly I'll be covering up in my next post. Can't wait for excitement! Meet you there again folks, bye! 🤟🏻