📜 ⬆️ ⬇️

Javascript: tracking variable value changes

The issue of tracking changes to variables (or properties of objects) in javascript arises, as a rule, among developers after some time spent writing code. At the very moment when the question “how to do it? " Is replaced by the question" how to do it more optimally? ".

Agree to “bind” a property that is responsible for some dynamic value of your web application, with the DOM tree update function, or with methods that build calculations to work only with the model in the future, without thinking about subsequent necessary manipulations - not only comfortable, but also beautiful in terms of architecture.

If you build your application on a library or framework where there is an implementation of this issue ( react suggests the setstate method, vue gives the user its own reactivity system ) then everything is clear.
')
However, the methods of implementing the task in pure javascript out of the box are somewhat more complicated than the simple ones and are not always convenient to use (Object.defineProperty (), Proxy). The super-light floss-js library (<1kb) is designed to provide functionality for tracking property changes and calling handler methods. Working under the hood with Object.defineProperty, the library stores real values ​​in a separate special data store, proxying them through user-defined properties and tracking access events (returns from the store) and changes (overwrites the value in the store and calls the user-defined handler function).

Simply put: floss-js ( github ) keeps track of the variables and properties of an object and executes custom code as they are modified.

image

Installation


Add a library to the project is very easy.


Event creation


Suppose there is a small web application that implements some kind of functionality. What exactly for us does not matter. In the application, there is a state variable that contains a string indicating the current state of the application (for example: loading, expectation of the user, user writing ..., saving ..., unexpected error, etc.); the value of a variable can change both due to data coming from the server, and due to user manipulations.

In DOM, there is a container for displaying notifications for the user:

 <div id="state"></div> 

We have already connected FLOSS.min.js and now we need to hang the handler: when the state value is changed, the function that updates the DOM tree should be called.

 /*      DOM */ let updateState = (state) => { document.querySelector('#state').innerHTML = state; } 

Next, hang the handler itself:

 /*     FLOSS */ FLOSS({ name: 'state', value: 'Waiting for status', action: (newState) => { updateState(newState); } }); 

Consider in more detail: name - the name of the variable or property, for changes that need to be monitored. If the variable does not exist, it will be created globally, as a property of the window object. If it is necessary to monitor the property of an object, then the object itself must also be passed to the bind property of the FLOSS function. value - the default value assigned to the variable. And finally, the action is a handler function, to which the new value of the variable is transferred, after the change. The first action is triggered after the creation of the FLOSS handler. Therefore, in this example, the updateState function will execute immediately and will display “Waiting for status” to the user. If the first call to action needs to be postponed until the change of the monitored variable is changed, then you can specify an additional parameter defer: true .

By implementing this example, you can set a different state directly in the console. The FLOSS handler will immediately respond and call a method that updates the DOM.

It's simple, is not it?

Let's look at another, more complex, example of the use of a micro library.
The situation is similar: it is necessary to track changes in the state of the application. However, the state itself is now stored in a special object and the notification text is a computed property.

 let server = { state: { 200: 'OK', 201: 'Created', 203: 'Non-Authoritative Information', 526: 'Invalid SSL Certificate' }, logs: '...', status: '200', notification: function(){ return `${this.state[this.status]}, status: ${this.status}` } } 

We are interested in the notificaion property. However, it is a function that generates a notification for the user. Accordingly, we will track the status property.

 FLOSS({ name: 'status', value: server.status, /*  value     */ action: function(){ updateState(server.notification()); }, defer: false, bind: server /* ,     */ }); 

Naturally, the use of state-tracking variable methods is not always advisable. Often there is no need for this technique, and if there is, then you can always implement your own narrowly focused method, which accepts a new value as input, mutates the necessary property, and also handlers that call all the necessary functions. However, if your child balances between a small application and an application that requires a foundation like REACT - with FLOSS, you can make the code more minimalistic and structured.

Thanks for attention.

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


All Articles