To avoid issues with re-calculating immediately on change while keeping reactive values in-sync, use reactive accessors to implement pull-based computed values. Propose using computed
for pull-based computed values that are kept synchronized and reactive
to run functionality on initialize and before beforeUpdate
.
Option 2 uses a single reactive:
label and can re-run blocks as-needed based on when reactive values are accessed. I think there are a few downsides to this (side effects could happen at strange times), but it's a bit simpler since it presents a single reactive API.
// Initialized with <Component a=15 />
export let a = 10;
let b = 20;
assert.equal(a, 15);
let c, d;
computed: c = a + 1;
computed: d = expensiveSum(a, b);
reactive: console.log(c); // -> 16 (on initialize)
assert.equal(d, 35);
function handle_click() {
a += 1;
assert.equal(c, 17);
b += 1;
assert.equal(d, 37);
}
Transforms roughly into:
function init($$self, $$initial_props, $$make_dirty, $$make_reactive) {
const __recompute = { flag: 1 | 2 | 4 };
const __dirty_a = () => { $$make_dirty('a'); __recompute.flag |= 1 | 2; };
const __dirty_b = () => { $$make_dirty('b'); __recompute.flag |= 2; };
const __dirty_c = () => { $$make_dirty('c'); __recompute.flag |= 4; };
let { a = 10 } = $$initial_props;
let b = 20;
assert.equal(a, 15);
let c, d;
const __c = $$make_reactive(__recompute, 1, () => { c = a + 1; __dirty_c(); });
const __d = $$make_reactive(__recompute, 2, () => { d = expensiveSum(a, b); $$make_dirty('d'); });
const __auto_0 = $$make_reactive(__recompute, 4, () => { console.log(c); }; __auto_0();
__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 = () => {
__c(); __d();
return { a, b, c, d };
};
$$self.synchronize = $$dirty => {
__auto_0();
}
}
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: 3 };
const __dirty_count = () => { $$make_dirty('count'); __recompute.flag |= 1; };
const __dirty_doubled = () => { $$make_dirty('doubled'); __recompute.flag |= 2; };
let count = 1;
let doubled;
let quadrupled;
__doubled = $$make_reactive(__recompute, 1, () => { doubled = count * 2; __dirty_doubled() });
__quadrupled = $$make_reactive(__recompute, 2, () => { quadrupled = doubled * 2; $$make_dirty('quadrupled') });
function handle_click() {
count += 1;
__dirty_count();
}
$$self.get = () => {
__doubled(); __quadrupled();
return { count, doubled, quadrupled, handle_click }
};
}