📜 ⬆️ ⬇️

About the main reason for the existence of modern JS frameworks



The author of the material, the translation of which we publish today, says that he very often had to see how web developers thoughtlessly use modern frameworks like React, Angular or Vue.js. These frameworks offer a lot of interesting things, but, as a rule, programmers, applying them, do not take into account the main reason for their existence. Usually the question: "Why do you use the X framework", you can hear the following answers, among which, however, there is no most important thing:


In fact, the most important, fundamental reason for using frameworks is that they help to solve the problem of synchronizing the user interface and the internal state of the application. This is an extremely difficult and important task, and we will talk about it today.

Why interface and state synchronization is important


Imagine that you are creating a web application, using which a user can send certain materials, like invitations, to many people, by entering their e-mail addresses on a special page. Entering the address in the field, the user presses the Enter key and the application saves the entered address and displays it on the page. The UX / UI designer made the following decision: if there is nothing in the application state, we show the input field with auxiliary text on the page, in other cases the same input field and already entered email addresses are displayed, to the right of each of which there is a button or link for remove address.
')

The two states of the form are the empty form, and the form with the addresses

As a repository of the state of such a form, something like an array of objects can be used, each of which contains an email address and some unique identifier. Adding a new address to the application by entering it in the field and pressing the Enter key results in placing this address in an array and updating the user interface. When you click the delete link, the address is removed from the array, and, again, the application interface is updated. It is easy to see that every time the state of the application changes, you need to update the user interface.

Why is this moment especially important? In order to understand this, we will try to implement this functionality in pure JavaScript and using some kind of framework.

Implementing a complex interface in pure javascript


Here is the implementation of the above interface on pure JS, prepared using CodePen.

Looking at the code of this implementation, you can estimate the amount of work needed to create a similar interface and internal mechanisms of the application without using any additional tools (by the way, using classic libraries like jQuery will lead to about the same development process and result) .

In this example, HTML forms the static structure of the page, and dynamic elements are created using JavaScript tools (using document.createElement ). This leads us to the first problem: JS code that describes the user interface does not have good readability, and using both it and HTML, we break the definition of interface elements into two parts. In a situation like this, we could use innerHTML , something that would work out would be more comprehensible, but this approach is less effective and can lead to cross-site scripting problems.

You could use the template engine here, but if you need to recreate a large DOM subtree, this leads to two more problems. Firstly, this is not particularly effective, and secondly, with this approach, you usually have to re-connect event handlers.

However, among the problems described above, there is no main one, which is that the user interface needs to be updated every time the application state changes. With each update of the state, serious efforts are required, expressed by the corresponding code, aimed at updating the user interface. For example, in our case, when adding an email address, you need 2 lines of code in order to update the state, and more than a dozen lines - in order to update the interface. It should be borne in mind that the interface in our example is maximally simplified.


The code required to update the status and user interface of the application

Such code is not only difficult to write and maintain. More importantly, it is very unreliable. It is very easy to break it. Imagine that we need to implement the ability to synchronize the address list with the server. To do this, you need to compare the data that are available in the application, so that received from the server. Here you will have to compare all the identifiers of the objects used to store the addresses, and the addresses themselves, since the application may well have copies of records with the same identifiers as the records on the server, but with different addresses.

To do this, you need to create a large amount of highly specialized code to organize effective changes to the DOM. In this case, if the slightest mistake is made, the synchronization of the interface with the data will break. This can be expressed in the absence of some data on the page, in the display of incorrect information, in the appearance of controls that do not respond to user input, or, even worse, cause the execution of incorrect actions (for example, the button for deleting an element affects the wrong element to which it corresponds in the interface).

As a result, support for synchronization of the interface and data implies writing a large amount of uniform and unreliable code. What to do? Referring to the declarative description of the interfaces.

Declarative interface description as a solution


The solution to the problem is not a powerful community of some framework, no additional tools, no ecosystem, and no third-party libraries. The main feature of the frameworks, which allows to solve the above problem, is that they allow you to implement interfaces that are guaranteed to be synchronized with the internal state of the application.

Actually, the ideal solution to the problem is described above, but in reality, this is so if the developer does not have to limit himself to certain rules that a particular framework may have (for example, the rule regarding the immunity of the application state).

Using the framework, we define the interface in one go, without having to write code to work with the interface when performing each action. This always gives the same visible result based on a specific state: the framework automatically updates the interface after a state change.

About interface and state synchronization strategies


There are two basic strategies for interface synchronization and status.


About web components


React, Angular, and Vue.js are often compared to web components . This demonstrates the fact that many people do not understand the main opportunity that these frameworks provide to the developer. This, as we have already found out, is the synchronization of the interface and the internal state of the application. Web components do not provide such features. They give the developer the <template> tag , but not the interface and state matching mechanism. If a programmer uses web components and maintains the synchronization of the interface and the state of the application, he will have to solve this task on his own, or use something like Stencil.js (this library, like React, uses Virtual DOM).

Note that the strength of such a decision is not the use of web components, but the ability to maintain synchronization of the interface and state. Web components do not contain built-in tools for such synchronization. There will have to either use a third-party library, or do everything manually. In fact, it is impossible to create a complex, efficient and simple interface in terms of support in pure JavaScript. This is the main reason why developers need modern frameworks.

Experiment: own framework


Let's experiment, rewrite our example , which is based on pure JS, using the Virtual DOM implementation , while not resorting to the use of frameworks. The fact that we succeed, it is possible to call our own framework. Here is its base, the base class on which the components will be based.


The core of a modern framework of its own design

Here is the rewritten component AddressList (here, babel is used to support JSX).


Application interface implemented by means of a proprietary framework

Now the user interface is defined in a declarative style, while we did not use existing frameworks. We can implement new logic, which changes the state as we need, without having to write additional code in order to keep the interface and state of the application in sync. Problem solved!

Now, with the exception of event handlers, this is all very similar to a React application. There are, for example, the methods render() , componentDidMount() , setState() . After the basic problem of synchronization of the interface and the internal state of the application has been solved, other possibilities are integrated into the resulting system in a completely natural way.

The full code for this project can be found in this GitHub repository.

Results


Summing up, we can draw the following conclusions:


Dear readers! In your opinion, is the synchronization of the interface and the state of the application really the main problem that modern front-end frameworks solve?

Source: https://habr.com/ru/post/353074/


All Articles