This has been tested in v146.
Vanilla JS in the simplest way I could imagine, allows to enable tracking of existing objects’ properties (potentially in somebody else’s code you have no full control of).
This solution solves two problems:
-
A situation where different functions (that can be called in unknown order before or after the render call) need to know if the property in question has changed since the last function call.
-
Immediate notification (event like) of the change that will execute some code.
First, I create new properties on the object and replace the old ones with getters and setters to make it “reactive”:
// arr = [cam.quaternion, Obj3D.position, ...]
// mailbox = {}
const enableTracking = (arr, mailbox) => {
arr.forEach(obj => {
const q = obj.isQuaternion;
const prop = q ? ['_x', '_y', '_z'] : ['x', 'y', 'z'];
if (q) prop.push('_w');
for(const p of prop) {
const np = '_' + p;
Object.defineProperty(obj, np, {
configurable: true,
enumerable: true,
value: obj[p],
writable: true,
});
Object.defineProperty(obj, p, {
configurable: true,
enumerable: true,
get: () => obj[np],
set: v => {
obj[np] = v;
for (const pr in mailbox) mailbox[pr] = true;
},
});
}
});
};
mailbox is an object inside which all interested parties can create their properties (subscribe). All those properties will be triggered by the setter.
Use case to solve problem 1:
const mailbox = { cam_check: false };
enableTracking([camera.position, camera.quaternion], mailbox);
const someFunction = () => {
if(mailbox.cam_check) {
mailbox.cam_check = false;
// do something
}
};
Use case to solve problem 2 (event-like notification):
const mailbox = {
set cam_pos_quat_changed(v) { rebuildCamCoordSys() },
};
...
enableTracking([camera.position, camera.quaternion], mailbox);