How State Management  works? Dead simple SM in Vanilla JavaScript
Tags: javascript, beginners, webdev, react
Published: 2021-03-09 14:04:40

Dead simple State Management in Vanilla JavaScript
It's been years now since you started using Redux, MobX or even plain React Hooks and have no idea how state management works and why it works the way it works? I'll show you the dead simple bottom level of work in state management sans any optimization or other bells and whistles.

We will be building a stupidly simple plain ol' HTML page with script tags in it.

```html
<!DOCTYPE html>
<html>
  <head>
    <title>State Management in Vanilla JS</title>
  </head>

  <body>
    <div id="app"></div>

    <script>
      // 
    </script>
  </body>
</html>
```

Now let's write some JavaScript.
 
**NOTE:** TL;DR; is down below ⏬

```js
const App = function _App() {  
  return `
    <h1>Hello Vanilla JS</h1>
    <div>Example of state management in Vanilla JS</div>
  `;
}
document.getElementById("app").innerHTML = App();
```

I could have simply declared as

```js
const App = function() { // ...
// or
const App = () => { // ...
```
But there's reason I didn't, which I'll explain later. Now, let's create some state 

```js
App.state = {
  count: 0,
  increment: () => {
    App.state.count++;
  }
};
```

A simple state created as a property on App function. 😉

_Wait! You can do that?_ 😲

Yes, everything in JavaScript is an object, and technically you can even do that on strings and numbers. That is why methods like `"hello world".toUppercase()` and `(12).toFixed(2)` would work. But the compiler doesn't allow you to define your own properties on a string or number.

Now that App has been made stateful, we shall integrate the state and add a click event listener at the end of file.

```js
`
  <h1>${_App.state.count}</h1>
  <button id="button">Increase</button>
`
// ...
document.getElementById("app").innerHTML = App();
// On Click Function
document
  .getElementById("button")
  .addEventListener("click", App.state.increment);
```

Note that I'm accessing App inside itself by neither `this` nor by `App` but by `_App`. This is called as "[Named function expression](https://developer.mozilla.org/en-US/docs/web/JavaScript/Reference/Operators/function#named_function_expression)"

There are two special things about Named function expression:
1. It allows the function to reference itself internally.
2. It is not visible outside of the function.

Even if I do something like this below, the code won't break.

```js
const Component = App;
App = null;
document.getElementById("app").innerHTML = Component();
```

Even when App has been reassigned to Component and then made to be null, the function itself remains intact and it refers itself as _App locally, hence it is not affected. Same as '`this`' in every other OOP programming language (But We all know how `this`  works in JavaScript)😅.

Now try running it (simply double click the index.html file). Notice that the on click function isn't working! 🙄 It's because the UI is not reflecting the latest state, let's fix that by re-rendering the elements. This can be done by running this code again when the state is updated.

```js
document.getElementById("app").innerHTML = App();
// On Click Function
document
  .getElementById("button")
  .addEventListener("click", App.state.increment);
```

Since this code is and will be repeated, we will extract it to a function

```js
const updateTree = () => {
  document.getElementById("app").innerHTML = App();
// On Click Function
  document
    .getElementById("button")
    .addEventListener("click", App.state.increment);
}
```

Now add a setState function 
```js
const setState = (callback) => {
  callback();
  updateTree(); // extracted function
}
```

and update the increment function as

```js
increment: () => {
  // Call our set state function
  setState(() => App.state.count++);
}
```

Now our App works as expected. And that's it! that's the end of Dead simple State Management in Vanilla JavaScript. However just using as it is would be consider as an awful and poor framework, not because of its lack of any bell and whistles worthy feature, but because it is poorly optimised, in fact it has no optimisation, but you already know this when I said _"…sans any optimization or other bells and whistles"_ in the beginning of this article.

Things to do,
1. Should not render the whole application to reflect a simple change.
2. As soon as we update to reflect the state, all the event listeners attached to DOM should not be lost and we shouldn't add new event listeners in its place.
3. The DOM elements that were unaffected and unchanged by state should not be forced to change. Changes should be as small as possible

So we shall few optimisations to our App like how React and similar library / framework does in the next upcoming article.

## TL;DR;
Here is the full HTML file we have coded so far.

```html
<!DOCTYPE html>
<html>
  <head>
    <title>State Management in Vanilla JS</title>
  </head>

  <body>
    <div id="app"></div>

    <script>
      const App = function _App() {
        return `
          <h1>Hello Vanilla JS!</h1>
          <div>
            Example of state management in Vanilla JS
          </div>
          <br />
          <h1>${_App.state.count}</h1>
          <button id="button">Increase</button>
        `;
      };

      App.state = {
        count: 0,
        increment: () => {
          setState(() => App.state.count++);
        }
      };

      const setState = (callback) => {
        callback();
        updateTree(); // extracted function
      }

      const updateTree = () => {
        document.getElementById("app").innerHTML = App();
        document
          .getElementById("button")
          .addEventListener("click", App.state.increment);
      };

      updateTree();
    </script>
  </body>
</html>
```


### Updates:
1. (13 Mar 2021) Added `setState` function, fixed few typos, added link for named function expression.