Reaktivität mit JavaScript Proxy
Was ist ein JavaScript Proxy?
Mit dem JavaScript Proxy
können Daten-Objekte mit einem "Vermittlungs-Objekt" erweitert werden.
Der Proxy kann dabei bestimmte Operationen abfangen die auf das Objekt und dessen Properties angewendet werden.
Dazu zählen zum Beispiel das Lesen einer Eigenschaft (get
) oder das Verändern einer Eigenschaft (set
).
Die Funktionalität lässt sich nutzen um zum Beispiel reaktive Objekte zu erzeugen, wie man
es aus bekannten JavaScript-Framework wie React oder Vue kennt.
Nur dass man mit Proxy kein Framework benötigt. Es funktioniert nativ im Browser.
let proxy = new Proxy(target, handler);
target
ist dabei das Objekt auf welches der Proxy angewendet wird.handler
enthält Methoden für die Manipulation des Objektes. Hier wird definiert wie das Objekt (target
) behandelt werden soll.
Anwendungsbeispiel
let product = {
id: 1,
name: 'T-Shirt',
size: 'L',
price: 9.99,
stock: 10,
};
let proxy = new Proxy(product, {
get(target, property) {
console.log(`read property: ${property} with value: ${target[property]}`);
return target[property];
},
set(target, property, value) {
console.log(`write property: ${property} with value: ${value} and old value: ${target[property]}`);
target[property] = value;
return true;
},
});
Wir definieren ein JavaScript-Objekt product
mit den Eigenschaften id
,
name
, size
, price
und stock
.
Dann wenden wir einen Proxy auf dieses Objekt an.
Jedes Mal wenn eine Eigenschaft von product
ausgelesen oder verändert wird, fängt der Proxy diesen
Vorgang ab und gibt uns eine Ausgabe in die Konsole.
Wenn eine Eigenschaft von product
verändert wird, greift die Set-Methode des Proxy und zeigt eine Ausgabe in der Browser-Konsole
product.stock = 12;
Das Gleiche Prinzip gilt auch für das Auslesen der Property-Werte.
Wenn zum Beispiel per console.log()
ein Property-Wert ausgelesen wird, greift die Proxy-Methode get
.
console.log(product.stock);
Der Zugriff auf eine mit Proxy
ausgewiesene Methode wird als Trap bezeichnet (engl. für Falle).
Der Proxy agiert praktisch als Mittelsmann zwischen dem Datenobjekt und den Zugriffen darauf.
Damit lassen sich grundlegende Operationen manipulieren, wie Property-Zuweisungen, Funktions- und Objektzugriffe.
Es lassen sich auf Validierungen umsetzen.
let proxy = new Proxy(product, {
get(target, property) {
if ('stock' === property) {
if (!Number.isInteger(value)) {
throw new TypeError('The stock value is not an integer');
}
console.warn('Sorry the product is out of stock');
}
return target[property];
},
});
Die Zuweisung product.stock = 'test';
wirft nun eine Exception: "Uncaught TypeError: The stock value is not an integer".
Diese können wir nutzen um eine bessere Datenintegrität zu geährlisten.
JavaScript Proxy für Reaktivität nutzen
Jetzt fragt man sich natürlich wie man das Ganze für Reaktivität nutzen kann. Das reaktive Objekt soll andere Komponenten der Anwendung automatisch informieren, wenn sich bestimmte Werte ändern. Man spricht dabei von einer reaktiven Anwendung oder data-driven-Anwendung. Sobald sich an den Daten etwas ändert, werden bestimmte Teile der Anwendung über die Änderung informiert und die Komponente kann zum Beispiel neu gerendert werden. Wir nutzen dafür ein Event-Mechanismus den wir bereits in diesem Tutorial beschrieben haben: Create a Event Bus with JavaScript
let proxy = new Proxy(product, {
get(target, property) {
EventBus.trigger('PROPERTY_GET', {
data: {
property: property,
value: target[property]
}
});
return target[property];
},
set(target, property, value) {
EventBus.trigger('PROPERTY_SET', {
data: {
property: property,
value: value,
oldValue: target[property]
}
});
target[property] = value;
return true;
},
});
Immer wenn auf eine Property von product
zugegriffen wird, wird das Event PROPERTY_GET
getriggert.
Wenn eine Property geändert wird, feuert das Event PROPERTY_SET
. Andere Komponenten können darauf hören.
EventBus.on('PROPERTY_SET', ({ data }) => {
console.log(`PROPERTY_SET: ${data.property} => ${data.value}`);
if ('price' === data.property) {
alert(`The product price has been changed: ${data.value}`);
}
});
Events logisch nutzen
Neben dem Lesen und Schreiben von Properties, kann das Event-Prinzip auch für logische Operationen genutzt werden. Beispielsweise kann geprüft werden ob ein Produkt nicht mehr verfügbar ist (out of stock). Komponenten in unserer Anwendung können darauf reagieren und zum Beispiel eine Warnmeldung anzeigen. Es können auch mehrere Komponenten gleichzeitig auf das Event reagieren.
let proxy = new Proxy(product, {
set(target, property, value) {
...
if (property === 'stock') {
if (0 === target[property]) {
EventBus.trigger('PRODUCT_OUT_OF_STOCK', {
data: {
property: property,
value: value,
oldValue: target[property]
}
});
}
}
return true;
},
});
Mehr Lesen
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy
- Create a Event Bus with JavaScript