To avoid issues with re-calculating immediately on change while keeping reactive values in-sync, use reactive accessors to implement pull-based reactive values.
// Initialized with <Component a=15 />
export let a = 10;
let b = 20;
assert.equal(a, 15);
let c, d;
reactive: c = a + 1;
reactive: {
d = expensiveSum(a, b);
console.log(d);
} // -> 16 (on initialize)
assert.equal(c, 16);
function handle_click() {
a += 1;
assert.equal(c, 17);
b += 1;
// -> 37
assert.equal(d, 37);
}
Transforms roughly into:
function init($$self, $$initial_props, $$make_dirty, $$make_reactive) {
const __recompute = { flags: 1 | 2 };
const __dirty_a = () => { $$make_dirty('a'); __recompute.flags |= 1 | 2 };
const __dirty_b = () => { $$make_dirty('b'); __recompute.flags |= 2; };
const __dirty_c = () => { $$make_dirty('c'); };
const __dirty_d = () => { $$make_dirty('d'); };
let { a = 10 } = $$initial_props;
let b = 20;
assert.equal(a, 15);
let c, d;
const __r_0 = $$make_reactive(__recompute, 1, () => {
c = a + 1;
__dirty_c();
}); __r_0();
const __c = __r_0;
const __r_1 = $$make_reactive(__recompute, 2, () => {
d = expensiveSum(a, b);
__dirty_d();
console.log(d);
}); __r_1();
const __d = __r_1;
__c();
assert.equal(c, 16);
__d();
assert.equal(d, 35);
function handle_click() {
a += 1;
__dirty_a();
__c();
assert.equal(c, 17);
b += 1;
__dirty_b();
__d();
assert.equal(d, 37);
}
$$self.get = () => {
return { a, b, c, d, handle_click };
};
$$self.synchronize = () => {
__r_0();
__r_1();
};
}
Where $$make_reactive
is roughly:
function $$make_reactive(recompute, id, compute) {
return () => {
if (recompute.flag & id) {
compute();
recompute.flag ^= id;
}
};
}
The doubled-quadrupled example from RFC#8 would look like:
function init($$self, $$initial_props, $$make_dirty, $$make_reactive) {
const __recompute = { flag: 1 | 2 };
const __dirty_count = () => { $$make_dirty('count'); __recompute.flag |= 1; };
const __dirty_doubled = () => { $$make_dirty('doubled'); __recompute.flag |= 2; };
const __dirty_quadrupled = () => { $$make_dirty('quadrupled'); };
let count = 1;
let doubled;
let quadrupled;
const __r_0 = $$make_reactive(__recompute, 1, () => {
doubled = count * 2;
__dirty_doubled()
}); __r_0();
const __doubled = __r_0;
const __r_1 = $$make_reactive(__recompute, 2, () => {
quadrupled = doubled * 2;
__dirty_quadrupled()
}); __r_1();
const __quadrupled = __r_1;
function handle_click() {
count += 1;
__dirty_count();
}
$$self.get = () => {
return { count, doubled, quadrupled, handle_click }
};
$$self.synchronize = () => {
__r_0();
__r_1();
}
}