I wonder how to subscribe to the changes of a JavaScript object e.g. like Redux does. I read through a lot of JS documentations but I couldn't find a non-deprecated way to handle this problem (Object.protype.watch()
as well as Object.observe()
are deprecated). Moreover I read a few Stackoverflow questions regarding this topic but they are all at least 5 years old. To visualize my problem I'll show an example.
This could be an object I want to watch for:
const store = {
anArray = [
'Hi',
'my',
'name',
'is'
]
}
.. and this a function which changes the store
object:
function addAName() {
store.anArray.push('Bob')
}
My goal in this example is to trigger the following function every time the store
object changes
function storeChanged() {
console.log('The store object has changed!')
}
Thank you in advance!
To prevent modification of JavaScript objects, one of the techniques is to use Object. freeze() . Freezing an object does not allow new properties to be added to an object and prevents from removing or altering the existing properties.
The watch() method watches for a property to be assigned a value and runs a function when that occurs.
Watch for Object Changes with JavaScript. Watching for changes to an object's property has always been a much sought after task; many shims have been used over the years to listen to object changes. These days we have better methods for listening to object changes: the Proxy API.
The value that gets passed in to the subscribe () callback, form, is simply a JavaScript object. As the form values change, this same object structure will be passed into the subscription with the updated form values.
There might be a better way than subscribing to a change event (which usually can be an expensive operation as it could be called many times) Subject/BehaviorSubject allows you to both publish as well as listen to changes.
As the form values change, this same object structure will be passed into the subscription with the updated form values. We get the sessionStorage object from the browser, and we associate the form values object to a key in the storage, in this case 'form'.
Have you tried using Proxy from ECMA6? I think this is what you are looking for You only have to define a function as the set of the validator of the Proxy like this:
let validator = {
set: function(target, key, value) {
console.log(`The property ${key} has been updated with ${value}`);
return true;
}
};
let store = new Proxy({}, validator);
store.a = 'hello';
// console => The property a has been updated with hello
You can use Object.defineproperty() to create reactive getters/setters. It has good browser support and looks handy.
function Store() {
let array = [];
Object.defineProperty(this, 'array', {
get: function() {
console.log('Get:', array);
return array;
},
set: function(value) {
array = value;
console.log('Set:', array)
}
});
}
var store = new Store();
store.array; //Get: []
store.array = [11]; //Set: [11]
store.array.push(5) //Set: [11, 5]
store.array = store.array.concat(1, 2, 3) //Set: [11, 5, 1, 2, 3]
To solve this problem without any indirections (in using object) you can use proxy.
By wrapping all objects with observalbe
you can edit your store frealy and _base
keeps track of which property has changed.
const observalbe = (target, callback, _base = []) => {
for (const key in target) {
if (typeof target[key] === 'object')
target[key] = observalbe(target[key], callback, [..._base, key])
}
return new Proxy(target, {
set(target, key, value) {
if (typeof value === 'object') value = observalbe(value, callback, [..._base, key])
callback([..._base, key], target[key] = value)
return value
}
})
}
const a = observalbe({
a: [1, 2, 3],
b: { c: { d: 1 } }
}, (key, val) => {
console.log(key, val);
})
a.a.push(1)
a.b.c.d = 1
a.b = {}
a.b.c = 1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With