y
to html<h1 id="y"></h1>
let state = { x: 1 };
function renderY() {
document.getElementById('y').innerText = `y = x + 1 = ${state.x + 1}`;
}
renderY();
function setState(newState) {
state = { ...state, ...newState} // newState Obj overrides original state obj prop
renderY();
}
setState({ x: 2 });
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
let value = state['x']; // grab value of x
Object.defineProperty(state, 'x', {
get() {
return value; // simply return value
},
set(newValue) {
value = newValue; // update value
renderY(); // run render function
}
});
let state = { x: 1 };
function renderY() {
document.getElementById('y').innerText = `y = x + 1 = ${state.x + 1}`;
}
renderY();
let value = state['x']; // grab value of x
Object.defineProperty(state, 'x', {
get() {
return value; // simply return value
},
set(newValue) {
value = newValue; // update value
renderY(); // run render function
}
});
x
and won't work for a nested objectfunction observable(obj) {
Object.keys(obj).forEach(key => {
let value = observable(obj[key);
Object.defineProperty(obj, key, {
get() {
return value;
},
set(newValue) {
value = newValue;
renderY();
}
})
});
return obj;
}
function observable(obj) {
Object.keys(obj).forEach(key => {
let value = observable(obj[key]);
Object.defineProperty(obj, key, {
get() {
return value;
},
set(newValue) {
value = newValue;
renderY();
}
});
});
return obj;
}
let state = observable({ x: 1 });
function renderY() {
document.getElementById('y').innerText = `y = x + 1 = ${state.x + 1}`;
}
renderY();
class Dep {
static job;
constructor() {
this.jobs = new Set();
}
depend() {
if (Dep.job) {
this.jobs.add(Dep.job);
}
}
notify() {
this.jobs.forEach(job => {
job();
})
}
}
Dep.job = null;
job
stores the current evaluating job.function observable(obj) {
Object.keys(obj).forEach(key => {
let value = observable(obj[key]);
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
dep.depend();
return value;
},
set(newValue) {
value = newValue;
dep.notify();
}
});
});
return obj;
}
class Dep {
static job;
constructor() {
this.jobs = new Set();
}
depend() {
if (Dep.job) {
this.jobs.add(Dep.job);
}
}
notify() {
this.jobs.forEach(job => {
job();
});
}
}
Dep.job = null;
function observable(obj) {
Object.keys(obj).forEach(key => {
let value = observable(obj[key]);
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
dep.depend();
return value;
},
set(newValue) {
value = newValue;
dep.notify()
}
});
});
return obj;
}
let state = observable({
x: 1
});
function renderY() {
document.getElementById("y").innerText = `y = x + 1 = ${state.x + 1}`;
}
Dep.job = renderY;
renderY();
// dont forget clear the current job
Dep.job = null;
class Dep {
static job;
constructor() {
this.subscribers = new Set();
}
depend() {
if (Dep.job) {
this.subscribers.add(Dep.job);
}
}
notify() {
this.subscribers.forEach(sub => {
sub();
});
}
}
Dep.job = null;
function observable(obj) {
Object.keys(obj).forEach(key => {
let value = observable(obj[key]);
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
dep.depend();
return value;
},
set(newValue) {
value = newValue;
dep.notify()
}
});
});
return obj;
}
let state = observable({
x: 1
});
function runner(job) {
Dep.job = job;
job();
Dep.job = null;
}
function renderY() {
document.getElementById("y").innerText = `y = x + 1 = ${state.x + 1}`;
}
runner(renderY);
runner(() => {
document.getElementById("state").innerText = JSON.stringify(state, null, 2);
});
runner(() => {
document.getElementById("x").innerText = `x = ${state.x}`;
});
Runner function
Observable function