In this post, I will try to convince you that the amount of complexity you bring into your project to synchronize your application state with what a user sees on a screen is not worth it. **Reactivity** is not worth it. It's not worth it to use weird abstractions like **JSX** or other languages which produces **HTML** or **JS**. Bringing in build systems, package managers with tons of dependencies and other type of complexity like **Virtual DOM** just to build the frontend of your application is also not worth it.
## What's the Selling Point of Modern Frameworks?
Let's take a look at what **React** uses as an example:
```jsx
function MyButton() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
);
}
```
The idea here is that you don't need to directly update the value of the button when the value of `count` is being changed. I understand that real examples are way more complex, and while this specific example may not appear particularly impressive, it serves as a demonstration of the framework's functionality.
I also understand that the same example in other frameworks like Svelte looks less weird. My point is here that we still can reduce the amount of complexity.
## Let's First Try VanillaJS (Attempt #1)
I think the example above can be rewritten in plain JS much easier:
```html
```
While I write these words, I can already hear the voices of people complaining about how this is insufficient, how it's silly to update the DOM directly, and how it's insane to keep the application state right within the attributes of elements. It's funny because I don't really have an application state here; all I have is the DOM that contains useful information which I can extract and use. And yes, for large projects, the solution above may not be the best approach because large applications actually must have some state. So, let's talk about **application state...**
## Application State Must Be Global
The idea is that we must attach certain objects to specific elements or components cause us a lot of troubles. For some reason, we decided that global objects are evil. However, I don't see any real objective reason to think like that. Sure, there may be name collisions, but those issues are easily detectable and avoidable simply by naming things in a more concrete and distinctive way.
For some reason, it's okay to have DOM which is global within `window`. It's okay to have global structures like `sessionStorage` and `localStorage` and many other things within `window`. But it's not okay to separate global state of your application. To me it's seems inconsistent and quite harmful.
## Still VanillaJS (Attempt #2)
Let's use now global state:
```html
```
As you can see, it's a bit better because we don't need the `data-count` attribute. In this case, we do use the application state, and yes, it's global.
But what if we have many more elements that must visualize data? What if we cannot attach event handlers in such a way where we can easily access our elements? I hear you, and I have a solution: ``.
## So What About Templates
There is a such thing in **HTML** like [`` elements](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template). The interesting thing about this element is that it's not rendered on page load, but we can instantiate it later in JavaScript code. Just imagine that you can use such an element to rerender your view each time the application state changes.
The only problem is that there is no built-in solition about how you can map your object to that template and also there is no default mechanism which allow you to release that template into DOM. But let's admit, it not something impossible to implement.
## Using `` (Attempt #3)
Image if you could do something like this right in **HTML**:
```html
```
Imagine that we had a function `mapToTemplate(template, state)` that can map state to the template and inject whole content of the template directly into the **HTML**. In the end it would look like:
```html
```
As you see, we still have the possibility to release the initial **``**. By using `data-object-name`, we can define a variable name that we can reference in the **HTML** content inside the template. Attribute `data-text` indicates the inner text of the element once the value of the attribute is processed.
To be more specific about how we are going to render our template, let's improve our solution:
```html
```
By using `data-insert-into`, we can specify element selector where our template will be rendered. In this case, we insert it inside of element `#box`. So, imagine that we clicked the button 3 times, this is how our **HTML** would look like:
```html
```
We can use `data-append-to="#box"`, our **HTML** code will look like:
```html
```
Or we can use `data-prepend-to="#box"`, then our code would look like:
```html
```
It's silly, sure. But it shows the power of such mechanism. You can already imagine, how much it's easier to share the state between many elements:
```html
```
As you can see, we can even potentially use such things like "for-each" templates, which can render nested structures. In the end, we would see:
```html
4
5
6
7
```
When we see the attribute `data-object-name`, we can appreciate the fact that this object can come from anywhere, it trully makes our template decoupled from any data source. This is true reusable components. Yes, you need to call rendering manually via `mapToTemplate`, but you gain a lot in return. You can come back to good old days and simply enjoy writing **HTML**. There's no need for strange state management libraries built upon a false sense of how an application state should be stored.
I am not going to dive into how `mapToTemplate` [is implemented](https://github.com/guseyn/ehtml). All I am trying to say is that there are more elegant ways to manage your state, and you can come up with your own.
## Conclusion
You can give me many arguments on why such approach sucks. Like for example, you can say that manipulating **DOM** directly is slow, only to then turn around and use a library which calculates diff between **DOM** and **Virtual DOM** and does those direct manipulations anyway. I apologize, but I find it difficult to take such arguments seriously anymore.
At the very least, I hope you understand the importance of trying to achieve good results with basic technologies like **HTML** and **JS** before diving into modern frameworks.